Commit | Line | Data |
---|---|---|
54cc8ed4 DE |
1 | /* Opcode table for the TXVU |
2 | Copyright 1998 Free Software Foundation, Inc. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 2, or (at your option) | |
7 | any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License along | |
15 | with this program; if not, write to the Free Software Foundation, Inc., | |
16 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | #include "ansidecl.h" | |
19 | #include "dis-asm.h" | |
20 | #include "opcode/txvu.h" | |
21 | ||
22 | #ifndef NULL | |
23 | #define NULL 0 | |
24 | #endif | |
25 | ||
26 | #if defined (__STDC__) || defined (ALMOST_STDC) | |
27 | #define XCONCAT2(a,b) a##b | |
28 | #else | |
29 | #define XCONCAT2(a,b) a/**/b | |
30 | #endif | |
31 | #define CONCAT2(a,b) XCONCAT2(a,b) | |
32 | ||
33 | /* ??? One can argue it's preferable to have the PARSE_FN support in tc-vxvu.c | |
34 | and the PRINT_FN support in txvu-dis.c. For this project I like having | |
35 | them all in one place. */ | |
36 | ||
37 | #define PARSE_FN(fn) \ | |
38 | static long CONCAT2 (parse_,fn) \ | |
39 | PARAMS ((char **, const char **)); | |
40 | #define INSERT_FN(fn) \ | |
41 | static TXVU_INSN CONCAT2 (insert_,fn) \ | |
42 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
43 | int, long, const char **)) | |
44 | #define EXTRACT_FN(fn) \ | |
45 | static long CONCAT2 (extract_,fn) \ | |
46 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
47 | int, int *)) | |
48 | #define PRINT_FN(fn) \ | |
49 | static void CONCAT2 (print_,fn) \ | |
50 | PARAMS ((disassemble_info *, TXVU_INSN, long)); | |
51 | ||
52 | PARSE_FN (dotdest); | |
71af45ec DE |
53 | INSERT_FN (dotdest); |
54 | EXTRACT_FN (dotdest); | |
54cc8ed4 DE |
55 | PRINT_FN (dotdest); |
56 | ||
eb7168e5 DE |
57 | PARSE_FN (dotdest1); |
58 | ||
59 | PARSE_FN (bc); | |
d1128f73 | 60 | EXTRACT_FN (bc); |
eb7168e5 | 61 | PRINT_FN (sdest); |
8ea2f96f | 62 | |
71af45ec DE |
63 | PARSE_FN (vfreg); |
64 | PRINT_FN (vfreg); | |
54cc8ed4 | 65 | |
0b988d39 DE |
66 | PARSE_FN (bcftreg); |
67 | PRINT_FN (bcftreg); | |
3f897263 DE |
68 | |
69 | PARSE_FN (accdest); | |
70 | PRINT_FN (accdest); | |
71 | ||
d1128f73 | 72 | INSERT_FN (xyz); |
3f897263 | 73 | |
0b988d39 DE |
74 | PARSE_FN (ireg); |
75 | PRINT_FN (ireg); | |
76 | ||
77 | PARSE_FN (freg); | |
78 | PRINT_FN (freg); | |
79 | ||
80 | PARSE_FN (ffstreg); | |
81 | INSERT_FN (ffstreg); | |
82 | EXTRACT_FN (ffstreg); | |
83 | PRINT_FN (ffstreg); | |
84 | ||
85 | PARSE_FN (vi01); | |
86 | PRINT_FN (vi01); | |
87 | ||
eb7168e5 DE |
88 | INSERT_FN (luimm12); |
89 | EXTRACT_FN (luimm12); | |
0b988d39 | 90 | |
8ea2f96f DE |
91 | INSERT_FN (luimm15); |
92 | EXTRACT_FN (luimm15); | |
93 | ||
3f897263 | 94 | /* Various types of TXVU operands, including insn suffixes. |
54cc8ed4 DE |
95 | |
96 | Fields are: | |
97 | ||
98 | BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN | |
99 | ||
100 | Operand values are 128 + table index. This allows ASCII chars to be | |
101 | included in the syntax spec. */ | |
102 | ||
103 | const struct txvu_operand txvu_operands[] = | |
104 | { | |
3f897263 | 105 | /* place holder (??? not sure if needed) */ |
54cc8ed4 DE |
106 | #define UNUSED 128 |
107 | { 0 }, | |
108 | ||
8ea2f96f | 109 | /* Operands that exist in the same place for essentially the same purpose |
eb7168e5 DE |
110 | in both upper and lower instructions. These don't have a U or L prefix. |
111 | Operands specific to the upper or lower instruction are so prefixed. */ | |
0b988d39 | 112 | |
8ea2f96f DE |
113 | /* Destination indicator attached to mnemonic, with leading '.'. |
114 | After parsing this, the value is stored in global `dest' so that the | |
115 | register parser can verify the same choice of xyzw is used. */ | |
116 | #define DOTDEST (UNUSED + 1) | |
54cc8ed4 | 117 | { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX, |
71af45ec | 118 | parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest }, |
54cc8ed4 | 119 | |
8ea2f96f DE |
120 | /* ft reg, with vector specification same as DOTDEST */ |
121 | #define VFTREG (DOTDEST + 1) | |
122 | { 5, TXVU_SHIFT_TREG, 0, parse_vfreg, 0, 0, print_vfreg }, | |
54cc8ed4 | 123 | |
8ea2f96f DE |
124 | /* fs reg, with vector specification same as DOTDEST */ |
125 | #define VFSREG (VFTREG + 1) | |
126 | { 5, TXVU_SHIFT_SREG, 0, parse_vfreg, 0, 0, print_vfreg }, | |
54cc8ed4 | 127 | |
8ea2f96f DE |
128 | /* fd reg, with vector specification same as DOTDEST */ |
129 | #define VFDREG (VFSREG + 1) | |
130 | { 5, TXVU_SHIFT_DREG, 0, parse_vfreg, 0, 0, print_vfreg }, | |
131 | ||
132 | /* Upper word operands. */ | |
54cc8ed4 | 133 | |
3f897263 | 134 | /* broadcast */ |
8ea2f96f | 135 | #define UBC (VFDREG + 1) |
d1128f73 | 136 | { 2, 0, TXVU_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest }, |
3f897263 DE |
137 | |
138 | /* ftreg in broadcast case */ | |
0b988d39 | 139 | #define UBCFTREG (UBC + 1) |
8ea2f96f | 140 | { 5, TXVU_SHIFT_TREG, 0, parse_bcftreg, 0, 0, print_bcftreg }, |
3f897263 DE |
141 | |
142 | /* accumulator dest */ | |
0b988d39 | 143 | #define UACCDEST (UBCFTREG + 1) |
d1128f73 | 144 | { 0, 0, 0, parse_accdest, 0, 0, print_accdest }, |
3f897263 DE |
145 | |
146 | /* The XYZ operand is a fake one that is used to ensure only "xyz" is | |
147 | specified. It simplifies the opmula and opmsub entries. */ | |
0b988d39 | 148 | #define UXYZ (UACCDEST + 1) |
d1128f73 | 149 | { 0, 0, TXVU_OPERAND_FAKE, 0, insert_xyz, 0, 0 }, |
3f897263 | 150 | |
0b988d39 DE |
151 | /* Lower word operands. */ |
152 | ||
97a6824d | 153 | /* 5 bit signed immediate. */ |
8ea2f96f | 154 | #define LIMM5 (UXYZ + 1) |
97a6824d | 155 | { 5, 6, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 }, |
8ea2f96f | 156 | |
97a6824d | 157 | /* 11 bit signed immediate. */ |
8ea2f96f | 158 | #define LIMM11 (LIMM5 + 1) |
97a6824d | 159 | { 11, 0, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 }, |
0b988d39 | 160 | |
8ea2f96f DE |
161 | /* 15 bit unsigned immediate. */ |
162 | #define LUIMM15 (LIMM11 + 1) | |
97a6824d | 163 | { 15, 0, 0, 0, insert_luimm15, extract_luimm15, 0 }, |
8ea2f96f DE |
164 | |
165 | /* ID register. */ | |
166 | #define LIDREG (LUIMM15 + 1) | |
167 | { 5, 6, 0, parse_ireg, 0, 0, print_ireg }, | |
168 | ||
0b988d39 | 169 | /* IS register. */ |
8ea2f96f | 170 | #define LISREG (LIDREG + 1) |
0b988d39 DE |
171 | { 5, 11, 0, parse_ireg, 0, 0, print_ireg }, |
172 | ||
173 | /* IT register. */ | |
174 | #define LITREG (LISREG + 1) | |
175 | { 5, 16, 0, parse_ireg, 0, 0, print_ireg }, | |
176 | ||
177 | /* FS reg, with FSF field selector. */ | |
178 | #define LFSFFSREG (LITREG + 1) | |
179 | { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg }, | |
180 | ||
181 | /* FS reg, no selector (choice of x,y,z,w is provided by opcode). */ | |
182 | #define LFSREG (LFSFFSREG + 1) | |
183 | { 5, 11, 0, parse_freg, 0, 0, print_freg }, | |
184 | ||
185 | /* FT reg, with FTF field selector. */ | |
186 | #define LFTFFTREG (LFSREG + 1) | |
187 | { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg }, | |
188 | ||
189 | /* VI01 register. */ | |
190 | #define LVI01 (LFTFFTREG + 1) | |
d1128f73 | 191 | { 0, 0, 0, parse_vi01, 0, 0, print_vi01 }, |
0b988d39 | 192 | |
97a6824d DE |
193 | /* 24 bit unsigned immediate. */ |
194 | #define LUIMM24 (LVI01 + 1) | |
0b988d39 DE |
195 | { 24, 0, 0, 0, 0, 0, 0 }, |
196 | ||
eb7168e5 | 197 | /* 12 bit unsigned immediate, split into 1 and 11 bit pieces. */ |
97a6824d | 198 | #define LUIMM12 (LUIMM24 + 1) |
eb7168e5 | 199 | { 12, 0, 0, 0, insert_luimm12, extract_luimm12, 0 }, |
0b988d39 | 200 | |
1a702a24 | 201 | /* 11 bit pc-relative signed immediate. */ |
eb7168e5 | 202 | #define LPCREL11 (LUIMM12 + 1) |
1a702a24 | 203 | { 11, 0, TXVU_OPERAND_SIGNED + TXVU_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 }, |
8ea2f96f | 204 | |
eb7168e5 DE |
205 | /* Destination indicator, single letter only, with leading '.'. */ |
206 | #define LDOTDEST1 (LPCREL11 + 1) | |
8ea2f96f DE |
207 | { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX, |
208 | /* Note that we borrow the insert/extract/print functions from the | |
209 | vector case. */ | |
eb7168e5 | 210 | parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest }, |
8ea2f96f | 211 | |
54cc8ed4 DE |
212 | /* end of list place holder */ |
213 | { 0 } | |
214 | }; | |
215 | \f | |
216 | /* Macros to put a field's value into the right place. */ | |
1a702a24 | 217 | /* ??? If assembler needs these, move to opcode/txvu.h. */ |
3f897263 | 218 | |
0b988d39 | 219 | /* value X, B bits, shift S */ |
1a702a24 | 220 | #define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s)) |
0b988d39 | 221 | |
8ea2f96f DE |
222 | /* Field value macros for both upper and lower instructions. |
223 | These shift a value into the right place in the instruction. */ | |
224 | ||
225 | /* [FI] T reg field (remember it's V for value, not vector, here). */ | |
1a702a24 | 226 | #define VT(x) V ((x), 5, TXVU_SHIFT_TREG) |
8ea2f96f | 227 | /* [FI] S reg field. */ |
1a702a24 | 228 | #define VS(x) V ((x), 5, TXVU_SHIFT_SREG) |
8ea2f96f | 229 | /* [FI] D reg field. */ |
1a702a24 | 230 | #define VD(x) V ((x), 5, TXVU_SHIFT_DREG) |
8ea2f96f | 231 | /* DEST field. */ |
1a702a24 | 232 | #define VDEST(x) V ((x), 4, 21) |
8ea2f96f DE |
233 | |
234 | /* Masks for fields in both upper and lower instructions. | |
235 | These mask out all bits but the ones for the field in the instruction. */ | |
236 | ||
237 | #define MT VT (~0) | |
238 | #define MS VS (~0) | |
239 | #define MD VD (~0) | |
240 | #define MDEST VDEST (~0) | |
241 | ||
0b988d39 | 242 | /* Upper instruction Value macros. */ |
54cc8ed4 | 243 | |
3f897263 | 244 | /* Upper Flag bits. */ |
1a702a24 | 245 | #define VUF(x) V ((x), 5, 27) |
3f897263 | 246 | /* Upper REServed two bits next to flag bits. */ |
1a702a24 | 247 | #define VURES(x) V ((x), 2, 25) |
0b988d39 | 248 | /* 4 bit opcode field. */ |
1a702a24 | 249 | #define VUOP4(x) V ((x), 4, 2) |
0b988d39 | 250 | /* 6 bit opcode field. */ |
1a702a24 | 251 | #define VUOP6(x) V ((x), 6, 0) |
0b988d39 | 252 | /* 9 bit opcode field. */ |
1a702a24 | 253 | #define VUOP9(x) V ((x), 9, 2) |
0b988d39 | 254 | /* 11 bit opcode field. */ |
1a702a24 | 255 | #define VUOP11(x) V ((x), 11, 0) |
0b988d39 | 256 | /* BroadCast field. */ |
1a702a24 | 257 | #define VUBC(x) V ((x), 2, 0) |
0b988d39 | 258 | |
8ea2f96f | 259 | /* Upper instruction field masks. */ |
0b988d39 DE |
260 | #define MUUBITS (VUF (~0) + VURES (~0)) |
261 | #define MURES VURES (~0) | |
262 | #define MUOP4 VUOP4 (~0) | |
263 | #define MUOP6 VUOP6 (~0) | |
264 | #define MUOP9 VUOP9 (~0) | |
265 | #define MUOP11 VUOP11 (~0) | |
266 | ||
1a702a24 DE |
267 | /* A space, separates instruction name (mnemonic + mnemonic operands) from |
268 | operands. */ | |
3f897263 | 269 | #define SP ' ' |
1a702a24 DE |
270 | /* Commas separate operands. */ |
271 | #define C ',' | |
272 | /* Special I,P,Q,R operands. */ | |
273 | #define I 'i' | |
274 | #define P 'p' | |
275 | #define Q 'q' | |
276 | #define R 'r' | |
3f897263 | 277 | |
54cc8ed4 DE |
278 | /* TXVU instructions. |
279 | [??? some of these comments are left over from the ARC port from which | |
280 | this code is borrowed, delete in time] | |
281 | ||
282 | Longer versions of insns must appear before shorter ones (if gas sees | |
283 | "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is | |
284 | junk). This isn't necessary for `ld' because of the trailing ']'. | |
285 | ||
286 | Instructions that are really macros based on other insns must appear | |
287 | before the real insn so they're chosen when disassembling. Eg: The `mov' | |
288 | insn is really the `and' insn. | |
289 | ||
290 | This table is best viewed on a wide screen (161 columns). I'd prefer to | |
291 | keep it this way. The rest of the file, however, should be viewable on an | |
292 | 80 column terminal. */ | |
293 | ||
294 | /* ??? This table also includes macros: asl, lsl, and mov. The ppc port has | |
295 | a more general facility for dealing with macros which could be used if | |
296 | we need to. */ | |
297 | ||
298 | /* These tables can't be `const' because members `next_asm' and `next_dis' are | |
299 | computed at run-time. We could split this into two, as that would put the | |
300 | constant stuff into a readonly section. */ | |
301 | ||
302 | struct txvu_opcode txvu_upper_opcodes[] = { | |
303 | ||
1a702a24 | 304 | /* Macros appear first, so the disassembler will try them first. */ |
54cc8ed4 | 305 | /* ??? Any aliases? */ |
1a702a24 | 306 | /* ??? When close to being finished, clean up by aligning fields. */ |
54cc8ed4 | 307 | |
3f897263 | 308 | /* The rest of these needn't be sorted, but it helps to find them if they are. */ |
1a702a24 DE |
309 | { "abs", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x1fd) }, |
310 | { "add", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x28) }, | |
311 | { "addi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x22) }, | |
312 | { "addq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x20) }, | |
313 | { "add", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (0) }, | |
314 | { "adda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bc) }, | |
315 | { "addai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23e) }, | |
316 | { "addaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23c) }, | |
317 | { "adda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0xf) }, | |
8ea2f96f | 318 | { "clip", { DOTDEST, SP, VFSREG }, MURES + MDEST + MT + MUOP11, VDEST (0xf) + VUOP11 (0x1ff) }, |
1a702a24 DE |
319 | { "ftoi0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17c) }, |
320 | { "ftoi4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17d) }, | |
321 | { "ftoi12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17e) }, | |
322 | { "ftoi15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17f) }, | |
323 | { "itof0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13c) }, | |
324 | { "itof4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13d) }, | |
325 | { "itof12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13e) }, | |
326 | { "itof15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13f) }, | |
327 | { "madd", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x29) }, | |
328 | { "maddi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x23) }, | |
329 | { "maddq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x21) }, | |
330 | { "madd", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x2) }, | |
331 | { "madda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bd) }, | |
332 | { "maddai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23f) }, | |
333 | { "maddaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23d) }, | |
334 | { "madda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x2f) }, | |
335 | { "max", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2b) }, | |
336 | { "maxi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x2d) }, | |
337 | { "max", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x4) }, | |
338 | /* ??? mini or min? */ | |
339 | { "mini", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2f) }, | |
d1128f73 | 340 | { "minii", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1f) }, |
1a702a24 DE |
341 | { "mini", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x5) }, |
342 | { "msub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2d) }, | |
343 | { "msubi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x27) }, | |
344 | { "msubq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x25) }, | |
345 | { "msub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x3) }, | |
346 | { "msuba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fd) }, | |
347 | { "msubai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27f) }, | |
348 | { "msubaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27d) }, | |
349 | { "msuba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x3f) }, | |
350 | { "mul", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2a) }, | |
351 | { "muli", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1e) }, | |
352 | { "mulq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x1c) }, | |
353 | { "mul", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (6) }, | |
354 | { "mula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2be) }, | |
355 | { "mulai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x1fe) }, | |
356 | { "mulaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x1fc) }, | |
357 | { "mula", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x6f) }, | |
8ea2f96f | 358 | { "nop", { 0 }, MURES + MDEST + MT + MS + MUOP11, VUOP11 (0x2ff) }, |
1a702a24 DE |
359 | { "opmula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP11, VUOP11 (0x2fe) }, |
360 | { "opmsub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP6, VUOP6 (0x2e) }, | |
361 | { "sub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2c) }, | |
362 | { "subi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x26) }, | |
363 | { "subq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x24) }, | |
364 | { "sub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (1) }, | |
365 | { "suba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fc) }, | |
366 | { "subai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27e) }, | |
367 | { "subaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27c) }, | |
368 | { "suba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x1f) } | |
54cc8ed4 | 369 | }; |
97a6824d | 370 | const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_upper_opcodes[0]); |
8ea2f96f DE |
371 | \f |
372 | /* Lower instruction Value macros. */ | |
373 | ||
374 | /* 6 bit opcode. */ | |
1a702a24 | 375 | #define VLOP6(x) V ((x), 6, 0) |
8ea2f96f | 376 | /* 7 bit opcode. */ |
1a702a24 | 377 | #define VLOP7(x) V ((x), 7, 25) |
8ea2f96f | 378 | /* 11 bit opcode. */ |
1a702a24 | 379 | #define VLOP11(x) V ((x), 11, 0) |
8ea2f96f | 380 | /* 11 bit immediate. */ |
1a702a24 | 381 | #define VLIMM11(x) V ((x), 11, 0) |
8ea2f96f | 382 | /* FTF field. */ |
1a702a24 | 383 | #define VLFTF(x) V ((x), 2, 23) |
8ea2f96f | 384 | /* FSF field. */ |
1a702a24 | 385 | #define VLFSF(x) V ((x), 2, 21) |
eb7168e5 | 386 | /* Upper bit of 12 bit unsigned immediate. */ |
1a702a24 | 387 | #define VLUIMM12TOP(x) V ((x), 1, 21) |
eb7168e5 DE |
388 | /* Upper 4 bits of 15 bit unsigned immediate. */ |
389 | #define VLUIMM15TOP(x) VDEST (x) | |
8ea2f96f DE |
390 | |
391 | /* Lower instruction field masks. */ | |
392 | #define MLOP6 VLOP6 (~0) | |
393 | #define MLOP7 VLOP7 (~0) | |
394 | #define MLOP11 VLOP11 (~0) | |
395 | #define MLIMM11 VLIMM11 (~0) | |
1a702a24 | 396 | #define MLB24 V (1, 1, 24) |
eb7168e5 DE |
397 | #define MLUIMM12TOP VLUIMM12TOP (~0) |
398 | /* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits. | |
8ea2f96f DE |
399 | The upper 1 bit is part of the `dest' field. This mask is for the |
400 | other 3 bits of the dest field. */ | |
1a702a24 | 401 | #define MLUIMM12UNUSED V (7, 3, 22) |
eb7168e5 | 402 | #define MLUIMM15TOP MDEST |
54cc8ed4 DE |
403 | |
404 | struct txvu_opcode txvu_lower_opcodes[] = { | |
405 | ||
1a702a24 | 406 | /* Macros appear first, so the disassembler will try them first. */ |
54cc8ed4 | 407 | /* ??? Any aliases? */ |
1a702a24 DE |
408 | /* ??? There isn't an explicit nop. Apparently it's "move vf0,vf0". */ |
409 | { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) }, | |
54cc8ed4 | 410 | |
0b988d39 | 411 | /* The rest of these needn't be sorted, but it helps to find them if they are. */ |
8ea2f96f | 412 | { "b", { SP, LPCREL11 }, MLOP7 + MDEST + MT + MS, VLOP7 (0x20) }, |
1a702a24 DE |
413 | { "bal", { SP, LITREG, C, LPCREL11 }, MLOP7 + MDEST + MS, VLOP7 (0x21) }, |
414 | { "div", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLOP11, VLOP7 (0x40) + VLOP11 (0x3bc) }, | |
415 | { "eatan", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) }, | |
416 | { "eatanxy", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77c) }, | |
417 | { "eatanxz", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77d) }, | |
418 | { "eexp", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) }, | |
419 | { "eleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x74e) }, | |
420 | { "ercpr", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) }, | |
421 | { "erleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73f) }, | |
422 | { "ersadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73d) }, | |
423 | { "ersqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) }, | |
424 | { "esadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73c) }, | |
425 | { "esin", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) }, | |
426 | { "esqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) }, | |
427 | { "esum", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) }, | |
428 | { "fcand", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x12) }, | |
429 | { "fceq", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) }, | |
8ea2f96f | 430 | { "fcget", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x1c) }, |
1a702a24 DE |
431 | { "fcor", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) }, |
432 | { "fcset", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) }, | |
433 | { "fmand", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1a) }, | |
434 | { "fmeq", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x18) }, | |
435 | { "fmor", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1b) }, | |
436 | { "fsand", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x16) }, | |
437 | { "fseq", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x14) }, | |
438 | { "fsor", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x17) }, | |
439 | { "fsset", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x15) }, | |
440 | { "iadd", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x30) }, | |
441 | { "iaddi", { SP, LITREG, C, LISREG, C, LIMM5 }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x32) }, | |
442 | { "iaddiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x08) }, | |
443 | { "iand", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) }, | |
444 | { "ibeq", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x28) }, | |
445 | { "ibgez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2f) }, | |
446 | { "iblez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2e) }, | |
447 | { "ibltz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2c) }, | |
448 | { "ibne", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x29) }, | |
8ea2f96f | 449 | /* FIXME: Need to not require commas around parens. */ |
1a702a24 DE |
450 | { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x04) }, |
451 | { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3fe) }, | |
452 | { "ior", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) }, | |
453 | { "isub", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x31) }, | |
454 | { "isubiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x09) }, | |
455 | { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x05) }, | |
456 | { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3ff) }, | |
457 | { "jalr", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x25) }, | |
8ea2f96f | 458 | { "jr", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x24) }, |
1a702a24 | 459 | { "lq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x00) }, |
8ea2f96f | 460 | /* FIXME: No commas around -/+. */ |
1a702a24 DE |
461 | { "lqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37e) }, |
462 | { "lqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37c) }, | |
eb7168e5 | 463 | /* Only a single VF reg is allowed here. We can use VFTREG because LDOTDEST1 |
8ea2f96f | 464 | handles verifying only a single choice of xyzw is present. */ |
1a702a24 DE |
465 | { "mfir", { LDOTDEST1, SP, VFTREG, C, LISREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fc) }, |
466 | { "mfp", { DOTDEST, SP, VFTREG, C, P }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x67c) }, | |
467 | { "move", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33c) }, | |
468 | { "mr32", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33d) }, | |
469 | { "mtir", { LDOTDEST1, SP, LITREG, C, LFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) }, | |
470 | { "rget", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43d) }, | |
471 | { "rinit", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) }, | |
472 | { "rnext", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43c) }, | |
473 | { "rsqrt", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3be) }, | |
474 | { "rxor", { R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) }, | |
475 | { "sq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x01) }, | |
8ea2f96f | 476 | /* FIXME: No commas around -/+. */ |
1a702a24 DE |
477 | { "sqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37f) }, |
478 | { "sqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37d) }, | |
479 | { "sqrt", { SP, Q, C, LFTFFTREG }, MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) }, | |
8ea2f96f DE |
480 | { "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) }, |
481 | { "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) }, | |
482 | { "xgkick", { LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) }, | |
483 | { "xitop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) }, | |
484 | { "xtop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) } | |
54cc8ed4 | 485 | }; |
97a6824d | 486 | const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]); |
8ea2f96f | 487 | \f |
54cc8ed4 DE |
488 | /* Indexed by first letter of opcode. Points to chain of opcodes with same |
489 | first letter. */ | |
490 | /* ??? One can certainly use a better hash. Later. */ | |
491 | static struct txvu_opcode *upper_opcode_map[26 + 1]; | |
492 | static struct txvu_opcode *lower_opcode_map[26 + 1]; | |
493 | ||
494 | /* Indexed by insn code. Points to chain of opcodes with same insn code. */ | |
1a702a24 DE |
495 | static struct txvu_opcode *upper_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1]; |
496 | static struct txvu_opcode *lower_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1]; | |
54cc8ed4 DE |
497 | \f |
498 | /* Initialize any tables that need it. | |
499 | Must be called once at start up (or when first needed). | |
500 | ||
501 | FLAGS is currently unused but is intended to control initialization. */ | |
502 | ||
503 | void | |
504 | txvu_opcode_init_tables (flags) | |
505 | int flags; | |
506 | { | |
507 | static int init_p = 0; | |
508 | ||
509 | /* We may be intentionally called more than once (for example gdb will call | |
510 | us each time the user switches cpu). These tables only need to be init'd | |
511 | once though. */ | |
512 | /* ??? We can remove the need for txvu_opcode_supported by taking it into | |
513 | account here, but I'm not sure I want to do that yet (if ever). */ | |
514 | if (!init_p) | |
515 | { | |
516 | int i,n; | |
517 | ||
518 | memset (upper_opcode_map, 0, sizeof (upper_opcode_map)); | |
519 | memset (upper_icode_map, 0, sizeof (upper_icode_map)); | |
520 | ||
521 | /* Scan the table backwards so macros appear at the front. */ | |
522 | for (i = txvu_upper_opcodes_count - 1; i >= 0; --i) | |
523 | { | |
524 | int opcode_hash = TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes[i].mnemonic); | |
525 | int icode_hash = TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes[i].value); | |
526 | ||
527 | txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash]; | |
528 | upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i]; | |
529 | ||
530 | txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash]; | |
531 | upper_icode_map[icode_hash] = &txvu_upper_opcodes[i]; | |
532 | } | |
533 | ||
534 | memset (lower_opcode_map, 0, sizeof (lower_opcode_map)); | |
535 | memset (lower_icode_map, 0, sizeof (lower_icode_map)); | |
536 | ||
537 | /* Scan the table backwards so macros appear at the front. */ | |
538 | for (i = txvu_lower_opcodes_count - 1; i >= 0; --i) | |
539 | { | |
540 | int opcode_hash = TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes[i].mnemonic); | |
541 | int icode_hash = TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes[i].value); | |
542 | ||
543 | txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash]; | |
544 | lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i]; | |
545 | ||
546 | txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash]; | |
547 | lower_icode_map[icode_hash] = &txvu_lower_opcodes[i]; | |
548 | } | |
549 | ||
550 | init_p = 1; | |
551 | } | |
552 | } | |
553 | ||
554 | /* Return the first insn in the chain for assembling upper INSN. */ | |
555 | ||
556 | const struct txvu_opcode * | |
557 | txvu_upper_opcode_lookup_asm (insn) | |
558 | const char *insn; | |
559 | { | |
560 | return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)]; | |
561 | } | |
562 | ||
563 | /* Return the first insn in the chain for assembling lower INSN. */ | |
564 | ||
565 | const struct txvu_opcode * | |
566 | txvu_lower_opcode_lookup_asm (insn) | |
567 | const char *insn; | |
568 | { | |
569 | return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)]; | |
570 | } | |
571 | ||
572 | /* Return the first insn in the chain for disassembling upper INSN. */ | |
573 | ||
574 | const struct txvu_opcode * | |
575 | txvu_upper_opcode_lookup_dis (insn) | |
576 | TXVU_INSN insn; | |
577 | { | |
578 | return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)]; | |
579 | } | |
580 | ||
581 | /* Return the first insn in the chain for disassembling lower INSN. */ | |
582 | ||
583 | const struct txvu_opcode * | |
584 | txvu_lower_opcode_lookup_dis (insn) | |
585 | TXVU_INSN insn; | |
586 | { | |
587 | return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)]; | |
588 | } | |
589 | \f | |
590 | /* Value of DEST in use. | |
71af45ec | 591 | Each of the registers must specify the same value as the opcode. |
54cc8ed4 DE |
592 | ??? Perhaps remove the duplication? */ |
593 | static int dest; | |
3f897263 DE |
594 | |
595 | /* Value of BC to use. | |
596 | The register specified for the ftreg must match the broadcast register | |
597 | specified in the opcode. */ | |
598 | static int bc; | |
54cc8ed4 DE |
599 | \f |
600 | /* Init fns. | |
601 | These are called before doing each of the respective activities. */ | |
602 | ||
603 | /* Called by the assembler before parsing an instruction. */ | |
604 | ||
605 | void | |
606 | txvu_opcode_init_parse () | |
607 | { | |
608 | dest = -1; | |
3f897263 | 609 | bc = -1; |
54cc8ed4 DE |
610 | } |
611 | ||
612 | /* Called by the disassembler before printing an instruction. */ | |
613 | ||
614 | void | |
615 | txvu_opcode_init_print () | |
616 | { | |
617 | dest = -1; | |
3f897263 | 618 | bc = -1; |
54cc8ed4 DE |
619 | } |
620 | \f | |
8ea2f96f | 621 | /* Multiple destination choice support. |
54cc8ed4 DE |
622 | The "dest" string selects any combination of x,y,z,w. |
623 | [The letters are ordered that way to follow the manual's style.] */ | |
624 | ||
eb7168e5 | 625 | /* Utility to parse a `dest' spec. |
71af45ec DE |
626 | Return the found value. |
627 | *PSTR is set to the character that terminated the parsing. | |
628 | It is up to the caller to do any error checking. */ | |
629 | ||
54cc8ed4 | 630 | static long |
eb7168e5 | 631 | _parse_dest (pstr) |
54cc8ed4 | 632 | char **pstr; |
54cc8ed4 DE |
633 | { |
634 | long dest = 0; | |
635 | ||
54cc8ed4 DE |
636 | while (**pstr) |
637 | { | |
638 | switch (**pstr) | |
639 | { | |
640 | case 'x' : case 'X' : dest |= TXVU_DEST_X; break; | |
641 | case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break; | |
642 | case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break; | |
643 | case 'w' : case 'W' : dest |= TXVU_DEST_W; break; | |
71af45ec | 644 | default : return dest; |
54cc8ed4 DE |
645 | } |
646 | ++*pstr; | |
647 | } | |
648 | ||
71af45ec DE |
649 | return dest; |
650 | } | |
651 | ||
652 | static long | |
653 | parse_dotdest (pstr, errmsg) | |
654 | char **pstr; | |
655 | const char **errmsg; | |
656 | { | |
657 | long dest; | |
658 | ||
659 | if (**pstr != '.') | |
660 | { | |
661 | *errmsg = "missing `.'"; | |
662 | return 0; | |
663 | } | |
664 | ||
665 | ++*pstr; | |
eb7168e5 | 666 | dest = _parse_dest (pstr); |
71af45ec DE |
667 | if (dest == 0 || isalnum (**pstr)) |
668 | { | |
669 | *errmsg = "invalid `dest'"; | |
670 | return 0; | |
671 | } | |
eb7168e5 | 672 | |
54cc8ed4 DE |
673 | *errmsg = NULL; |
674 | return dest; | |
675 | } | |
676 | ||
eb7168e5 DE |
677 | /* Parse a `dest' spec where only a single letter is allowed, |
678 | but the encoding handles all four. */ | |
8ea2f96f DE |
679 | |
680 | static long | |
eb7168e5 | 681 | parse_dotdest1 (pstr, errmsg) |
8ea2f96f DE |
682 | char **pstr; |
683 | const char **errmsg; | |
684 | { | |
eb7168e5 | 685 | char c; |
8ea2f96f DE |
686 | long dest; |
687 | ||
688 | if (**pstr != '.') | |
689 | { | |
690 | *errmsg = "missing `.'"; | |
691 | return 0; | |
692 | } | |
693 | ||
694 | ++*pstr; | |
695 | switch (**pstr) | |
696 | { | |
eb7168e5 DE |
697 | case 'x' : case 'X' : dest |= TXVU_DEST_X; break; |
698 | case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break; | |
699 | case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break; | |
700 | case 'w' : case 'W' : dest |= TXVU_DEST_W; break; | |
8ea2f96f DE |
701 | default : *errmsg = "invalid `dest'"; return 0; |
702 | } | |
eb7168e5 DE |
703 | ++*pstr; |
704 | c == tolower (**pstr); | |
705 | if (c == 'x' || c == 'y' || c == 'z' || c == 'w') | |
706 | { | |
707 | *errmsg = "only one of x,y,z,w can be specified"; | |
708 | return 0; | |
709 | } | |
710 | if (isalnum (**pstr)) | |
711 | { | |
712 | *errmsg = "invalid `dest'"; | |
713 | return 0; | |
714 | } | |
715 | ||
8ea2f96f DE |
716 | *errmsg = NULL; |
717 | return dest; | |
718 | } | |
719 | ||
71af45ec DE |
720 | static TXVU_INSN |
721 | insert_dotdest (insn, operand, mods, value, errmsg) | |
722 | TXVU_INSN insn; | |
723 | const struct txvu_operand *operand; | |
724 | int mods; | |
725 | long value; | |
726 | const char **errmsg; | |
727 | { | |
728 | /* Record the DEST value in use so the register parser can use it. */ | |
729 | dest = value; | |
730 | if (errmsg) | |
731 | *errmsg = NULL; | |
732 | return insn |= value << operand->shift; | |
733 | } | |
734 | ||
735 | static long | |
736 | extract_dotdest (insn, operand, mods, pinvalid) | |
737 | TXVU_INSN insn; | |
738 | const struct txvu_operand *operand; | |
739 | int mods; | |
740 | int *pinvalid; | |
741 | { | |
742 | /* Record the DEST value in use so the register printer can use it. */ | |
743 | dest = (insn >> operand->shift) & ((1 << operand->bits) - 1); | |
744 | return dest; | |
745 | } | |
746 | ||
eb7168e5 DE |
747 | /* Utility to print a multiple dest spec. */ |
748 | ||
54cc8ed4 | 749 | static void |
eb7168e5 | 750 | _print_dest (info, insn, value) |
54cc8ed4 DE |
751 | disassemble_info *info; |
752 | TXVU_INSN insn; | |
753 | long value; | |
754 | { | |
54cc8ed4 DE |
755 | if (value & TXVU_DEST_X) |
756 | (*info->fprintf_func) (info->stream, "x"); | |
757 | if (value & TXVU_DEST_Y) | |
758 | (*info->fprintf_func) (info->stream, "y"); | |
759 | if (value & TXVU_DEST_Z) | |
760 | (*info->fprintf_func) (info->stream, "z"); | |
761 | if (value & TXVU_DEST_W) | |
762 | (*info->fprintf_func) (info->stream, "w"); | |
763 | } | |
71af45ec DE |
764 | |
765 | static void | |
766 | print_dotdest (info, insn, value) | |
767 | disassemble_info *info; | |
768 | TXVU_INSN insn; | |
769 | long value; | |
770 | { | |
771 | (*info->fprintf_func) (info->stream, "."); | |
eb7168e5 DE |
772 | _print_dest (info, insn, value); |
773 | } | |
774 | \f | |
775 | /* Utilities for single destination choice handling. */ | |
776 | ||
777 | static long | |
778 | _parse_sdest (pstr, errmsg) | |
779 | char **pstr; | |
780 | const char **errmsg; | |
781 | { | |
782 | char c; | |
783 | long dest = 0; | |
784 | ||
785 | switch (**pstr) | |
786 | { | |
787 | case 'x' : case 'X' : dest = TXVU_SDEST_X; break; | |
788 | case 'y' : case 'Y' : dest = TXVU_SDEST_Y; break; | |
789 | case 'z' : case 'Z' : dest = TXVU_SDEST_Z; break; | |
790 | case 'w' : case 'W' : dest = TXVU_SDEST_W; break; | |
791 | default : *errmsg = "only one of x,y,z,w can be specified"; return 0; | |
792 | } | |
793 | ++*pstr; | |
794 | c == tolower (**pstr); | |
795 | if (c == 'x' || c == 'y' || c == 'z' || c == 'w') | |
796 | { | |
797 | *errmsg = "only one of x,y,z,w can be specified"; | |
798 | return 0; | |
799 | } | |
800 | if (isalnum (**pstr)) | |
801 | { | |
802 | *errmsg = "invalid `dest'"; | |
803 | return 0; | |
804 | } | |
805 | ||
806 | *errmsg = NULL; | |
807 | return dest; | |
808 | } | |
809 | ||
810 | static void | |
811 | print_sdest (info, insn, value) | |
812 | disassemble_info *info; | |
813 | TXVU_INSN insn; | |
814 | long value; | |
815 | { | |
816 | char c; | |
817 | ||
818 | switch (value) | |
819 | { | |
820 | case TXVU_SDEST_X : c = 'x'; break; | |
821 | case TXVU_SDEST_Y : c = 'y'; break; | |
822 | case TXVU_SDEST_Z : c = 'z'; break; | |
823 | case TXVU_SDEST_W : c = 'w'; break; | |
824 | } | |
825 | ||
826 | (*info->fprintf_func) (info->stream, "%c", c); | |
827 | } | |
828 | \f | |
829 | /* Broadcase field. */ | |
830 | ||
831 | static long | |
832 | parse_bc (pstr, errmsg) | |
833 | char **pstr; | |
834 | const char **errmsg; | |
835 | { | |
836 | long value = _parse_sdest (pstr, errmsg); | |
837 | ||
838 | if (*errmsg) | |
839 | return 0; | |
840 | /* Save value for later verification in register parsing. */ | |
841 | bc = value; | |
842 | return value; | |
843 | } | |
844 | ||
845 | /* During the extraction process, save the bc field for use in | |
846 | printing the bc register. */ | |
847 | ||
848 | static long | |
849 | extract_bc (insn, operand, mods, pinvalid) | |
850 | TXVU_INSN insn; | |
851 | const struct txvu_operand *operand; | |
852 | int mods; | |
853 | int *pinvalid; | |
854 | { | |
855 | bc = insn & 3; | |
856 | return bc; | |
71af45ec | 857 | } |
54cc8ed4 DE |
858 | \f |
859 | static long | |
71af45ec | 860 | parse_vfreg (pstr, errmsg) |
54cc8ed4 DE |
861 | char **pstr; |
862 | const char **errmsg; | |
863 | { | |
864 | char *str = *pstr; | |
865 | char *start; | |
866 | long reg; | |
71af45ec | 867 | int reg_dest; |
54cc8ed4 DE |
868 | |
869 | if (tolower (str[0]) != 'v' | |
870 | || tolower (str[1]) != 'f') | |
871 | { | |
872 | *errmsg = "unknown register"; | |
873 | return 0; | |
874 | } | |
875 | ||
876 | /* FIXME: quick hack until the framework works. */ | |
877 | start = str = str + 2; | |
878 | while (*str && isdigit (*str)) | |
879 | ++str; | |
880 | reg = atoi (start); | |
eb7168e5 DE |
881 | if (reg < 0 || reg > 31) |
882 | { | |
883 | *errmsg = "invalid register number"; | |
884 | return 0; | |
885 | } | |
886 | reg_dest = _parse_dest (&str); | |
71af45ec DE |
887 | if (reg_dest == 0 || isalnum (*str)) |
888 | { | |
889 | *errmsg = "invalid `dest'"; | |
890 | return 0; | |
891 | } | |
892 | if (reg_dest != dest) | |
893 | { | |
894 | *errmsg = "register `dest' does not match instruction `dest'"; | |
895 | return 0; | |
896 | } | |
54cc8ed4 DE |
897 | *pstr = str; |
898 | *errmsg = NULL; | |
899 | return reg; | |
900 | } | |
901 | ||
902 | static void | |
71af45ec | 903 | print_vfreg (info, insn, value) |
54cc8ed4 DE |
904 | disassemble_info *info; |
905 | TXVU_INSN insn; | |
906 | long value; | |
907 | { | |
d1128f73 | 908 | (*info->fprintf_func) (info->stream, "vf%02ld", value); |
eb7168e5 | 909 | _print_dest (info, insn, dest); |
3f897263 DE |
910 | } |
911 | \f | |
912 | /* FT register in broadcast case. */ | |
913 | ||
914 | static long | |
0b988d39 | 915 | parse_bcftreg (pstr, errmsg) |
3f897263 DE |
916 | char **pstr; |
917 | const char **errmsg; | |
918 | { | |
919 | char *str = *pstr; | |
920 | char *start; | |
921 | long reg; | |
922 | int reg_bc; | |
923 | ||
924 | if (tolower (str[0]) != 'v' | |
925 | || tolower (str[1]) != 'f') | |
926 | { | |
927 | *errmsg = "unknown register"; | |
928 | return 0; | |
929 | } | |
930 | ||
931 | /* FIXME: quick hack until the framework works. */ | |
932 | start = str = str + 2; | |
933 | while (*str && isdigit (*str)) | |
934 | ++str; | |
935 | reg = atoi (start); | |
eb7168e5 DE |
936 | if (reg < 0 || reg > 31) |
937 | { | |
938 | *errmsg = "invalid register number"; | |
939 | return 0; | |
940 | } | |
941 | reg_bc = _parse_sdest (&str, errmsg); | |
3f897263 DE |
942 | if (*errmsg) |
943 | return 0; | |
944 | if (reg_bc != bc) | |
945 | { | |
946 | *errmsg = "register `bc' does not match instruction `bc'"; | |
947 | return 0; | |
948 | } | |
949 | *pstr = str; | |
950 | *errmsg = NULL; | |
951 | return reg; | |
952 | } | |
953 | ||
954 | static void | |
0b988d39 | 955 | print_bcftreg (info, insn, value) |
3f897263 DE |
956 | disassemble_info *info; |
957 | TXVU_INSN insn; | |
958 | long value; | |
959 | { | |
d1128f73 | 960 | (*info->fprintf_func) (info->stream, "vf%02ld", value); |
eb7168e5 | 961 | print_sdest (info, insn, bc); |
3f897263 DE |
962 | } |
963 | \f | |
964 | /* ACC handling. */ | |
965 | ||
966 | static long | |
967 | parse_accdest (pstr, errmsg) | |
968 | char **pstr; | |
969 | const char **errmsg; | |
970 | { | |
971 | char *str = *pstr; | |
972 | long acc_dest = 0; | |
973 | ||
974 | if (strncasecmp (str, "acc", 3) != 0) | |
975 | { | |
976 | *errmsg = "expecting `acc'"; | |
977 | return 0; | |
978 | } | |
979 | str += 3; | |
eb7168e5 | 980 | acc_dest = _parse_dest (&str); |
3f897263 DE |
981 | if (acc_dest == 0 || isalnum (*str)) |
982 | { | |
983 | *errmsg = "invalid `dest'"; | |
984 | return 0; | |
985 | } | |
986 | if (acc_dest != dest) | |
987 | { | |
988 | *errmsg = "acc `dest' does not match instruction `dest'"; | |
989 | return 0; | |
990 | } | |
991 | *pstr = str; | |
992 | *errmsg = NULL; | |
993 | /* Value isn't used, but we must return something. */ | |
994 | return 0; | |
995 | } | |
996 | ||
997 | static void | |
998 | print_accdest (info, insn, value) | |
999 | disassemble_info *info; | |
1000 | TXVU_INSN insn; | |
1001 | long value; | |
1002 | { | |
1003 | (*info->fprintf_func) (info->stream, "acc"); | |
d1128f73 | 1004 | _print_dest (info, insn, dest); |
3f897263 DE |
1005 | } |
1006 | \f | |
1007 | /* XYZ operand handling. | |
1008 | This simplifies the opmula,opmsub entries by keeping them equivalent to | |
1009 | the others. */ | |
1010 | ||
d1128f73 DE |
1011 | static TXVU_INSN |
1012 | insert_xyz (insn, operand, mods, value, errmsg) | |
1013 | TXVU_INSN insn; | |
1014 | const struct txvu_operand *operand; | |
1015 | int mods; | |
1016 | long value; | |
3f897263 DE |
1017 | const char **errmsg; |
1018 | { | |
1019 | if (dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z)) | |
1020 | { | |
1021 | *errmsg = "expecting `xyz' for `dest' value"; | |
d1128f73 | 1022 | return insn; |
3f897263 | 1023 | } |
d1128f73 | 1024 | return insn; |
3f897263 | 1025 | } |
0b988d39 | 1026 | \f |
eb7168e5 DE |
1027 | /* F[ST] register using selector in F[ST]F field. |
1028 | Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator | |
1029 | followed by the 5 bit register number. */ | |
0b988d39 DE |
1030 | |
1031 | static long | |
1032 | parse_ffstreg (pstr, errmsg) | |
1033 | char **pstr; | |
1034 | const char **errmsg; | |
1035 | { | |
1036 | char *str = *pstr; | |
1037 | char *start; | |
eb7168e5 | 1038 | int reg, xyzw; |
0b988d39 DE |
1039 | |
1040 | if (tolower (str[0]) != 'v' | |
1041 | || tolower (str[1]) != 'f') | |
1042 | { | |
1043 | *errmsg = "unknown register"; | |
1044 | return 0; | |
1045 | } | |
1046 | ||
1047 | /* FIXME: quick hack until the framework works. */ | |
1048 | start = str = str + 2; | |
1049 | while (*str && isdigit (*str)) | |
1050 | ++str; | |
1051 | reg = atoi (start); | |
eb7168e5 | 1052 | if (reg < 0 || reg > 31) |
0b988d39 | 1053 | { |
eb7168e5 | 1054 | *errmsg = "invalid register number"; |
0b988d39 DE |
1055 | return 0; |
1056 | } | |
eb7168e5 DE |
1057 | xyzw = _parse_sdest (&str, errmsg); |
1058 | if (*errmsg) | |
1059 | return 0; | |
0b988d39 DE |
1060 | *pstr = str; |
1061 | *errmsg = NULL; | |
eb7168e5 | 1062 | return reg | (xyzw << 5); |
0b988d39 DE |
1063 | } |
1064 | ||
1065 | static void | |
1066 | print_ffstreg (info, insn, value) | |
1067 | disassemble_info *info; | |
1068 | TXVU_INSN insn; | |
1069 | long value; | |
1070 | { | |
eb7168e5 DE |
1071 | (*info->fprintf_func) (info->stream, "vf%ld", value & TXVU_MASK_REG); |
1072 | print_sdest (info, insn, (value >> 5) & 3); | |
0b988d39 DE |
1073 | } |
1074 | ||
0b988d39 DE |
1075 | static TXVU_INSN |
1076 | insert_ffstreg (insn, operand, mods, value, errmsg) | |
1077 | TXVU_INSN insn; | |
1078 | const struct txvu_operand *operand; | |
1079 | int mods; | |
1080 | long value; | |
1081 | const char **errmsg; | |
1082 | { | |
eb7168e5 DE |
1083 | if (operand->shift == TXVU_SHIFT_SREG) |
1084 | return insn | VLFSF (value >> 5) | VS (value); | |
1085 | else | |
1086 | return insn | VLFTF (value >> 5) | VT (value); | |
0b988d39 DE |
1087 | } |
1088 | ||
1089 | static long | |
1090 | extract_ffstreg (insn, operand, mods, pinvalid) | |
1091 | TXVU_INSN insn; | |
1092 | const struct txvu_operand *operand; | |
1093 | int mods; | |
1094 | int *pinvalid; | |
1095 | { | |
eb7168e5 DE |
1096 | if (operand->shift == TXVU_SHIFT_SREG) |
1097 | return (((insn & VLFSF (~0)) >> 21) << 5) | VS (insn); | |
1098 | else | |
1099 | return (((insn & VLFTF (~0)) >> 21) << 5) | VT (insn); | |
0b988d39 DE |
1100 | } |
1101 | \f | |
1102 | /* F register. */ | |
1103 | ||
1104 | static long | |
1105 | parse_freg (pstr, errmsg) | |
1106 | char **pstr; | |
1107 | const char **errmsg; | |
1108 | { | |
1109 | char *str = *pstr; | |
1110 | char *start; | |
1111 | long reg; | |
1112 | int reg_bc; | |
1113 | ||
1114 | if (tolower (str[0]) != 'v' | |
1115 | || tolower (str[1]) != 'f') | |
1116 | { | |
1117 | *errmsg = "unknown register"; | |
1118 | return 0; | |
1119 | } | |
1120 | ||
1121 | /* FIXME: quick hack until the framework works. */ | |
1122 | start = str = str + 2; | |
1123 | while (*str && isdigit (*str)) | |
1124 | ++str; | |
1125 | reg = atoi (start); | |
eb7168e5 | 1126 | if (reg < 0 || reg > 31) |
0b988d39 | 1127 | { |
eb7168e5 | 1128 | *errmsg = "invalid register number"; |
0b988d39 DE |
1129 | return 0; |
1130 | } | |
1131 | *pstr = str; | |
1132 | *errmsg = NULL; | |
1133 | return reg; | |
1134 | } | |
1135 | ||
1136 | static void | |
1137 | print_freg (info, insn, value) | |
1138 | disassemble_info *info; | |
1139 | TXVU_INSN insn; | |
1140 | long value; | |
1141 | { | |
1142 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
0b988d39 DE |
1143 | } |
1144 | \f | |
1145 | /* I register. */ | |
1146 | ||
1147 | static long | |
1148 | parse_ireg (pstr, errmsg) | |
1149 | char **pstr; | |
1150 | const char **errmsg; | |
1151 | { | |
1152 | char *str = *pstr; | |
1153 | char *start; | |
1154 | long reg; | |
1155 | int reg_bc; | |
1156 | ||
1157 | if (tolower (str[0]) != 'v' | |
eb7168e5 | 1158 | || tolower (str[1]) != 'i') |
0b988d39 DE |
1159 | { |
1160 | *errmsg = "unknown register"; | |
1161 | return 0; | |
1162 | } | |
1163 | ||
1164 | /* FIXME: quick hack until the framework works. */ | |
1165 | start = str = str + 2; | |
1166 | while (*str && isdigit (*str)) | |
1167 | ++str; | |
1168 | reg = atoi (start); | |
eb7168e5 | 1169 | if (reg < 0 || reg > 31) |
0b988d39 | 1170 | { |
eb7168e5 | 1171 | *errmsg = "invalid register number"; |
0b988d39 DE |
1172 | return 0; |
1173 | } | |
1174 | *pstr = str; | |
1175 | *errmsg = NULL; | |
1176 | return reg; | |
1177 | } | |
1178 | ||
1179 | static void | |
1180 | print_ireg (info, insn, value) | |
1181 | disassemble_info *info; | |
1182 | TXVU_INSN insn; | |
1183 | long value; | |
1184 | { | |
eb7168e5 | 1185 | (*info->fprintf_func) (info->stream, "vi%ld", value); |
0b988d39 DE |
1186 | } |
1187 | \f | |
1188 | /* VI01 register. */ | |
1189 | ||
1190 | static long | |
1191 | parse_vi01 (pstr, errmsg) | |
1192 | char **pstr; | |
1193 | const char **errmsg; | |
1194 | { | |
1195 | char *str = *pstr; | |
1196 | char *start; | |
1197 | long reg; | |
1198 | int reg_bc; | |
1199 | ||
1200 | if (tolower (str[0]) != 'v' | |
eb7168e5 | 1201 | || tolower (str[1]) != 'i') |
0b988d39 DE |
1202 | { |
1203 | *errmsg = "unknown register"; | |
1204 | return 0; | |
1205 | } | |
1206 | ||
1207 | /* FIXME: quick hack until the framework works. */ | |
1208 | start = str = str + 2; | |
1209 | while (*str && isdigit (*str)) | |
1210 | ++str; | |
1211 | reg = atoi (start); | |
eb7168e5 | 1212 | if (reg != 1) |
0b988d39 | 1213 | { |
eb7168e5 | 1214 | *errmsg = "vi01 required here"; |
0b988d39 DE |
1215 | return 0; |
1216 | } | |
1217 | *pstr = str; | |
1218 | *errmsg = NULL; | |
1219 | return reg; | |
1220 | } | |
1221 | ||
1222 | static void | |
1223 | print_vi01 (info, insn, value) | |
1224 | disassemble_info *info; | |
1225 | TXVU_INSN insn; | |
1226 | long value; | |
1227 | { | |
eb7168e5 | 1228 | (*info->fprintf_func) (info->stream, "vi01"); |
0b988d39 DE |
1229 | } |
1230 | \f | |
eb7168e5 | 1231 | /* Lower instruction 12 bit unsigned immediate. */ |
0b988d39 DE |
1232 | |
1233 | static TXVU_INSN | |
eb7168e5 | 1234 | insert_luimm12 (insn, operand, mods, value, errmsg) |
0b988d39 DE |
1235 | TXVU_INSN insn; |
1236 | const struct txvu_operand *operand; | |
1237 | int mods; | |
1238 | long value; | |
1239 | const char **errmsg; | |
1240 | { | |
eb7168e5 | 1241 | return insn | VLUIMM12TOP ((value & (1 << 11)) != 0) | VLIMM11 (value); |
0b988d39 DE |
1242 | } |
1243 | ||
1244 | static long | |
eb7168e5 | 1245 | extract_luimm12 (insn, operand, mods, pinvalid) |
0b988d39 DE |
1246 | TXVU_INSN insn; |
1247 | const struct txvu_operand *operand; | |
1248 | int mods; | |
1249 | int *pinvalid; | |
1250 | { | |
eb7168e5 | 1251 | return (((insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (insn); |
0b988d39 | 1252 | } |
8ea2f96f DE |
1253 | \f |
1254 | /* Lower instruction 15 bit unsigned immediate. */ | |
1255 | ||
1256 | static TXVU_INSN | |
1257 | insert_luimm15 (insn, operand, mods, value, errmsg) | |
1258 | TXVU_INSN insn; | |
1259 | const struct txvu_operand *operand; | |
1260 | int mods; | |
1261 | long value; | |
1262 | const char **errmsg; | |
1263 | { | |
eb7168e5 | 1264 | return insn | VLUIMM15TOP (value >> 11) | VLIMM11 (value); |
8ea2f96f DE |
1265 | } |
1266 | ||
1267 | static long | |
1268 | extract_luimm15 (insn, operand, mods, pinvalid) | |
1269 | TXVU_INSN insn; | |
1270 | const struct txvu_operand *operand; | |
1271 | int mods; | |
1272 | int *pinvalid; | |
1273 | { | |
eb7168e5 | 1274 | return (((insn & MLUIMM15TOP) >> 21) << 11) | VLIMM11 (insn); |
8ea2f96f | 1275 | } |