summaryrefslogtreecommitdiffstats
path: root/meta-xilinx-bsp/recipes-microblaze/binutils/binutils-2.29/0008-Add-new-MicroBlaze-bit-field-instructions.patch
blob: 0bc01177980dfe7cec11fadf4cb792725806e375 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
From 5c4dacaae2ba93569c1d37cda9859c57d6649dc0 Mon Sep 17 00:00:00 2001
From: Nagaraju Mekala <nagaraju.mekala@xilinx.com>
Date: Mon, 28 Aug 2017 19:54:01 -0700
Subject: [PATCH] Add new MicroBlaze bit-field instructions

This patches adds new bsefi and bsifi instructions. BSEFI- The
instruction shall extract a bit field from a register and place it
right-adjusted in the destination register. The other bits in the
destination register shall be set to zero BSIFI- The instruction shall
insert a right-adjusted bit field from a register at another position in
the destination register. The rest of the bits in the destination
register shall be unchanged

Signed-off-by: Nagaraju Mekala <nagaraju.mekala@xilinx.com>
Signed-off-by: Manjukumar Matha <manjukumar.harthikote-matha@xilinx.com>
Upstream-Status: Pending
---
 gas/config/tc-microblaze.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
 opcodes/microblaze-dis.c   | 16 +++++++++++
 opcodes/microblaze-opc.h   | 12 +++++++-
 opcodes/microblaze-opcm.h  |  6 +++-
 4 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index e135547e62..34cb80fac2 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -909,7 +909,7 @@ md_assemble (char * str)
   unsigned reg2;
   unsigned reg3;
   unsigned isize;
-  unsigned int immed, temp;
+  unsigned int immed, immed2, temp;
   expressionS exp;
   char name[20];
 
@@ -1164,7 +1164,76 @@ md_assemble (char * str)
       inst |= (reg2 << RA_LOW) & RA_MASK;
       inst |= (immed << IMM_LOW) & IMM5_MASK;
       break;
+ case INST_TYPE_RD_R1_IMM5_IMM5:
+      if (strcmp (op_end, ""))
+        op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
+      else
+	{
+          as_fatal (_("Error in statement syntax"));
+          reg1 = 0;
+        }
+      if (strcmp (op_end, ""))
+        op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
+      else
+	{
+          as_fatal (_("Error in statement syntax"));
+          reg2 = 0;
+        }
+
+      /* Check for spl registers.  */
+      if (check_spl_reg (&reg1))
+        as_fatal (_("Cannot use special register with this instruction"));
+      if (check_spl_reg (&reg2))
+        as_fatal (_("Cannot use special register with this instruction"));
 
+      /* Width immediate value.  */
+      if (strcmp (op_end, ""))
+        op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH);
+      else
+        as_fatal (_("Error in statement syntax"));
+      if (exp.X_op != O_constant)
+	{
+          as_warn (_("Symbol used as immediate width value for bit field instruction"));
+          immed = 1;
+        }
+      else
+        immed = exp.X_add_number;
+      if (opcode->instr == bsefi && immed > 31)
+        as_fatal (_("Width value must be less than 32"));
+
+      /* Shift immediate value.  */
+      if (strcmp (op_end, ""))
+        op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM);
+      else
+        as_fatal (_("Error in statement syntax"));
+      if (exp.X_op != O_constant)
+	    {
+          as_warn (_("Symbol used as immediate shift value for bit field instruction"));
+          immed2 = 0;
+        }
+      else
+	    {
+          output = frag_more (isize);
+          immed2 = exp.X_add_number;
+	    }
+      if (immed2 != (immed2 % 32))
+	    {
+          as_warn (_("Shift value greater than 32. using <value %% 32>"));
+          immed2 = immed2 % 32;
+        }
+
+      /* Check combined value.  */
+      if (immed + immed2 > 32)
+        as_fatal (_("Width value + shift value must not be greater than 32"));
+
+      inst |= (reg1 << RD_LOW) & RD_MASK;
+      inst |= (reg2 << RA_LOW) & RA_MASK;
+      if (opcode->instr == bsefi)
+        inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */
+      else
+        inst |= ((immed + immed2 - 1) & IMM5_MASK) << IMM_WIDTH_LOW; /* bsifi */
+      inst |= (immed2 << IMM_LOW) & IMM5_MASK;
+      break;
     case INST_TYPE_R1_R2:
       if (strcmp (op_end, ""))
         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
diff --git a/opcodes/microblaze-dis.c b/opcodes/microblaze-dis.c
index 6a174b0eb9..80a47ad2fc 100644
--- a/opcodes/microblaze-dis.c
+++ b/opcodes/microblaze-dis.c
@@ -73,6 +73,18 @@ get_field_imm5_mbar (long instr)
   return(strdup(tmpstr));
 }
 
+static char *
+get_field_imm5width (long instr)
+{
+  char tmpstr[25];
+
+  if (instr & 0x00004000)
+    sprintf (tmpstr, "%d", (short)(((instr & IMM5_WIDTH_MASK) >> IMM_WIDTH_LOW))); /* bsefi */
+ else
+    sprintf (tmpstr, "%d", (short)(((instr & IMM5_WIDTH_MASK) >> IMM_WIDTH_LOW) - ((instr & IMM5_MASK) >> IMM_LOW) + 1)); /* bsifi */
+  return (strdup (tmpstr));
+}
+
 static char *
 get_field_rfsl (long instr)
 {
@@ -396,6 +408,10 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
         /* For mbar 16 or sleep insn.  */
         case INST_TYPE_NONE:
           break;
+        /* For bit field insns.  */
+	    case INST_TYPE_RD_R1_IMM5_IMM5:
+          print_func (stream, "\t%s, %s, %s, %s", get_field_rd (inst),get_field_r1(inst),get_field_imm5width (inst), get_field_imm5 (inst));
+	     break;
 	/* For tuqula instruction */
 	case INST_TYPE_RD:
 	  print_func (stream, "\t%s", get_field_rd (inst));
diff --git a/opcodes/microblaze-opc.h b/opcodes/microblaze-opc.h
index a64f8362da..afb34989d9 100644
--- a/opcodes/microblaze-opc.h
+++ b/opcodes/microblaze-opc.h
@@ -59,6 +59,9 @@
 /* For mbar.  */
 #define INST_TYPE_IMM5 20
 
+/* For bsefi and bsifi */
+#define INST_TYPE_RD_R1_IMM5_IMM5  21
+
 #define INST_TYPE_NONE 25
 
 
@@ -89,7 +92,9 @@
 #define OPCODE_MASK_H124  0xFFFF07FF /* High 16, and low 11 bits.  */
 #define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits.  */
 #define OPCODE_MASK_H3  0xFC000600  /* High 6 bits and bits 21, 22.  */
+#define OPCODE_MASK_H3B 0xFC00C600  /* High 6 bits and bits 16, 17, 21, 22.  */
 #define OPCODE_MASK_H32 0xFC00FC00  /* High 6 bits and bit 16-21.  */
+#define OPCODE_MASK_H32B 0xFC00C000  /* High 6 bits and bit 16, 17.  */
 #define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits.  */
 #define OPCODE_MASK_H35B 0xFC0004FF /* High 6 bits and low 9 bits.  */
 #define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26.  */
@@ -102,7 +107,7 @@
 #define DELAY_SLOT 1
 #define NO_DELAY_SLOT 0
 
-#define MAX_OPCODES 299
+#define MAX_OPCODES 301
 
 struct op_code_struct
 {
@@ -159,6 +164,8 @@ struct op_code_struct
   {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst },
   {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst },
   {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst },
+  {"bsefi", INST_TYPE_RD_R1_IMM5_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64004000, OPCODE_MASK_H32B, bsefi, barrel_shift_inst },
+  {"bsifi", INST_TYPE_RD_R1_IMM5_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64008000, OPCODE_MASK_H32B, bsifi, barrel_shift_inst },
   {"or",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, microblaze_or, logical_inst },
   {"and",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, microblaze_and, logical_inst },
   {"xor",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, microblaze_xor, logical_inst },
@@ -438,5 +445,8 @@ char pvr_register_prefix[] = "rpvr";
 #define MIN_IMM5  ((int) 0x00000000)
 #define MAX_IMM5  ((int) 0x0000001f)
 
+#define MIN_IMM_WIDTH  ((int) 0x00000001)
+#define MAX_IMM_WIDTH  ((int) 0x00000020)
+
 #endif /* MICROBLAZE_OPC */
 
diff --git a/opcodes/microblaze-opcm.h b/opcodes/microblaze-opcm.h
index 21a3dc8d76..dd6be7f65c 100644
--- a/opcodes/microblaze-opcm.h
+++ b/opcodes/microblaze-opcm.h
@@ -29,7 +29,7 @@ enum microblaze_instr
   addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul,
   mulh, mulhu, mulhsu,swapb,swaph,
   idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
-  ncget, ncput, muli, bslli, bsrai, bsrli, mului,
+  ncget, ncput, muli, bslli, bsrai, bsrli, bsefi, bsifi, mului,
   /* 'or/and/xor' are C++ keywords.  */
   microblaze_or, microblaze_and, microblaze_xor,
   andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16,
@@ -129,6 +129,7 @@ enum microblaze_instr_type
 #define RB_LOW  11 /* Low bit for RB.  */
 #define IMM_LOW  0 /* Low bit for immediate.  */
 #define IMM_MBAR 21 /* low bit for mbar instruction.  */
+#define IMM_WIDTH_LOW 6 /* Low bit for immediate width */
 
 #define RD_MASK 0x03E00000
 #define RA_MASK 0x001F0000
@@ -141,6 +142,9 @@ enum microblaze_instr_type
 /* Imm mask for mbar.  */
 #define IMM5_MBAR_MASK 0x03E00000
 
+/* Imm mask for extract/insert width. */
+#define IMM5_WIDTH_MASK 0x000007C0
+
 /* FSL imm mask for get, put instructions.  */
 #define  RFSL_MASK 0x000000F
 
-- 
2.15.0