1 /* Opcode table for the TXVU
2 Copyright 1998 Free Software Foundation, Inc.
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)
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.
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. */
21 #include "opcode/txvu.h"
27 #if defined (__STDC__) || defined (ALMOST_STDC)
28 #define XCONCAT2(a,b) a##b
30 #define XCONCAT2(a,b) a/**/b
32 #define CONCAT2(a,b) XCONCAT2(a,b)
39 static int lookup_keyword_value
PARAMS ((const keyword
*, const char *, int));
40 static const char *lookup_keyword_name
PARAMS ((const keyword
*table
, int));
42 static char *scan_symbol
PARAMS ((char *));
44 /* Return non-zero if CH is a character that may appear in a symbol. */
45 /* FIXME: This will need revisiting. */
46 #define issymchar(ch) (isalnum (ch) || ch == '_')
48 #define SKIP_BLANKS(var) while (isspace (*(var))) ++(var)
50 /* ??? One can argue it's preferable to have the PARSE_FN support in tc-txvu.c
51 and the PRINT_FN support in txvu-dis.c. For this project I like having
52 them all in one place. */
54 #define PARSE_FN(fn) \
55 static long CONCAT2 (parse_,fn) \
56 PARAMS ((char **, const char **));
57 #define INSERT_FN(fn) \
58 static void CONCAT2 (insert_,fn) \
59 PARAMS ((TXVU_INSN *, const struct txvu_operand *, \
60 int, long, const char **))
61 #define EXTRACT_FN(fn) \
62 static long CONCAT2 (extract_,fn) \
63 PARAMS ((TXVU_INSN *, const struct txvu_operand *, \
65 #define PRINT_FN(fn) \
66 static void CONCAT2 (print_,fn) \
67 PARAMS ((disassemble_info *, TXVU_INSN *, long));
101 EXTRACT_FN (ffstreg
);
108 EXTRACT_FN (luimm12
);
110 INSERT_FN (luimm12up6
);
113 EXTRACT_FN (luimm15
);
115 /* Various types of TXVU operands, including insn suffixes.
119 BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
121 Operand values are 128 + table index. This allows ASCII chars to be
122 included in the syntax spec. */
124 const struct txvu_operand txvu_operands
[] =
126 /* place holder (??? not sure if needed) */
130 /* Operands that exist in the same place for essentially the same purpose
131 in both upper and lower instructions. These don't have a U or L prefix.
132 Operands specific to the upper or lower instruction are so prefixed. */
134 /* Destination indicator attached to mnemonic, with leading '.' or '/'.
135 After parsing this, the value is stored in global `dest' so that the
136 register parser can verify the same choice of xyzw is used. */
137 #define DOTDEST (UNUSED + 1)
138 { 4, TXVU_SHIFT_DEST
, TXVU_OPERAND_SUFFIX
,
139 parse_dotdest
, insert_dotdest
, extract_dotdest
, print_dotdest
},
141 /* ft reg, with vector specification same as DOTDEST */
142 #define VFTREG (DOTDEST + 1)
143 { 5, TXVU_SHIFT_TREG
, 0, parse_vfreg
, 0, 0, print_vfreg
},
145 /* fs reg, with vector specification same as DOTDEST */
146 #define VFSREG (VFTREG + 1)
147 { 5, TXVU_SHIFT_SREG
, 0, parse_vfreg
, 0, 0, print_vfreg
},
149 /* fd reg, with vector specification same as DOTDEST */
150 #define VFDREG (VFSREG + 1)
151 { 5, TXVU_SHIFT_DREG
, 0, parse_vfreg
, 0, 0, print_vfreg
},
153 /* Upper word operands. */
156 #define UBC (VFDREG + 1)
157 { 2, 0, TXVU_OPERAND_SUFFIX
, parse_bc
, 0, extract_bc
, print_sdest
},
159 /* ftreg in broadcast case */
160 #define UBCFTREG (UBC + 1)
161 { 5, TXVU_SHIFT_TREG
, 0, parse_bcftreg
, 0, 0, print_bcftreg
},
163 /* accumulator dest */
164 #define UACCDEST (UBCFTREG + 1)
165 { 0, 0, 0, parse_accdest
, 0, 0, print_accdest
},
167 /* The XYZ operand is a fake one that is used to ensure only "xyz" is
168 specified. It simplifies the opmula and opmsub entries. */
169 #define UXYZ (UACCDEST + 1)
170 { 0, 0, TXVU_OPERAND_FAKE
, 0, insert_xyz
, 0, 0 },
172 /* Lower word operands. */
174 /* 5 bit signed immediate. */
175 #define LIMM5 (UXYZ + 1)
176 { 5, 6, TXVU_OPERAND_SIGNED
, 0, 0, 0, 0 },
178 /* 11 bit signed immediate. */
179 #define LIMM11 (LIMM5 + 1)
180 { 11, 0, TXVU_OPERAND_SIGNED
, 0, 0, 0, 0 },
182 /* 15 bit unsigned immediate. */
183 #define LUIMM15 (LIMM11 + 1)
184 { 15, 0, 0, 0, insert_luimm15
, extract_luimm15
, 0 },
187 #define LIDREG (LUIMM15 + 1)
188 { 5, 6, 0, parse_ireg
, 0, 0, print_ireg
},
191 #define LISREG (LIDREG + 1)
192 { 5, 11, 0, parse_ireg
, 0, 0, print_ireg
},
195 #define LITREG (LISREG + 1)
196 { 5, 16, 0, parse_ireg
, 0, 0, print_ireg
},
198 /* FS reg, with FSF field selector. */
199 #define LFSFFSREG (LITREG + 1)
200 { 5, 11, 0, parse_ffstreg
, insert_ffstreg
, extract_ffstreg
, print_ffstreg
},
202 /* FS reg, no selector (choice of x,y,z,w is provided by opcode). */
203 #define LFSREG (LFSFFSREG + 1)
204 { 5, 11, 0, parse_freg
, 0, 0, print_freg
},
206 /* FT reg, with FTF field selector. */
207 #define LFTFFTREG (LFSREG + 1)
208 { 5, 16, 0, parse_ffstreg
, insert_ffstreg
, extract_ffstreg
, print_ffstreg
},
211 #define LVI01 (LFTFFTREG + 1)
212 { 0, 0, 0, parse_vi01
, 0, 0, print_vi01
},
214 /* 24 bit unsigned immediate. */
215 #define LUIMM24 (LVI01 + 1)
216 { 24, 0, 0, 0, 0, 0, 0 },
218 /* 12 bit unsigned immediate, split into 1 and 11 bit pieces. */
219 #define LUIMM12 (LUIMM24 + 1)
220 { 12, 0, 0, 0, insert_luimm12
, extract_luimm12
, 0 },
222 /* upper 6 bits of 12 bit unsigned immediate */
223 #define LUIMM12UP6 (LUIMM12 + 1)
224 { 12, 0, 0, 0, insert_luimm12up6
, extract_luimm12
, 0 },
226 /* 11 bit pc-relative signed immediate. */
227 #define LPCREL11 (LUIMM12UP6 + 1)
228 { 11, 0, TXVU_OPERAND_SIGNED
+ TXVU_OPERAND_RELATIVE_BRANCH
, 0, 0, 0, 0 },
230 /* Destination indicator, single letter only, with leading '.'. */
231 #define LDOTDEST1 (LPCREL11 + 1)
232 { 4, TXVU_SHIFT_DEST
, TXVU_OPERAND_SUFFIX
,
233 /* Note that we borrow the insert/extract/print functions from the
235 parse_dotdest1
, insert_dotdest
, extract_dotdest
, print_dotdest
},
237 /* Destination indicator, single letter only, no leading '.'. */
238 #define LDEST1 (LDOTDEST1 + 1)
239 { 0, 0, 0, parse_dest1
, 0, 0, print_dest1
},
241 /* end of list place holder */
245 /* Macros to put a field's value into the right place. */
246 /* ??? If assembler needs these, move to opcode/txvu.h. */
248 /* value X, B bits, shift S */
249 #define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s))
251 /* Field value macros for both upper and lower instructions.
252 These shift a value into the right place in the instruction. */
254 /* [FI] T reg field (remember it's V for value, not vector, here). */
255 #define VT(x) V ((x), 5, TXVU_SHIFT_TREG)
256 /* [FI] S reg field. */
257 #define VS(x) V ((x), 5, TXVU_SHIFT_SREG)
258 /* [FI] D reg field. */
259 #define VD(x) V ((x), 5, TXVU_SHIFT_DREG)
261 #define VDEST(x) V ((x), 4, 21)
263 /* Masks for fields in both upper and lower instructions.
264 These mask out all bits but the ones for the field in the instruction. */
269 #define MDEST VDEST (~0)
271 /* Upper instruction Value macros. */
273 /* Upper Flag bits. */
274 #define VUF(x) V ((x), 5, 27)
275 /* Upper REServed two bits next to flag bits. */
276 #define VURES(x) V ((x), 2, 25)
277 /* 4 bit opcode field. */
278 #define VUOP4(x) V ((x), 4, 2)
279 /* 6 bit opcode field. */
280 #define VUOP6(x) V ((x), 6, 0)
281 /* 9 bit opcode field. */
282 #define VUOP9(x) V ((x), 9, 2)
283 /* 11 bit opcode field. */
284 #define VUOP11(x) V ((x), 11, 0)
285 /* BroadCast field. */
286 #define VUBC(x) V ((x), 2, 0)
288 /* Upper instruction field masks. */
289 #define MUUBITS (VUF (~0) + VURES (~0))
290 #define MURES VURES (~0)
291 #define MUOP4 VUOP4 (~0)
292 #define MUOP6 VUOP6 (~0)
293 #define MUOP9 VUOP9 (~0)
294 #define MUOP11 VUOP11 (~0)
296 /* A space, separates instruction name (mnemonic + mnemonic operands) from
299 /* Commas separate operands. */
301 /* Special I,P,Q,R operands. */
307 /* TXVU instructions.
308 [??? some of these comments are left over from the ARC port from which
309 this code is borrowed, delete in time]
311 Longer versions of insns must appear before shorter ones (if gas sees
312 "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
313 junk). This isn't necessary for `ld' because of the trailing ']'.
315 Instructions that are really macros based on other insns must appear
316 before the real insn so they're chosen when disassembling. Eg: The `mov'
317 insn is really the `and' insn.
319 This table is best viewed on a wide screen (161 columns). I'd prefer to
320 keep it this way. The rest of the file, however, should be viewable on an
321 80 column terminal. */
323 /* ??? This table also includes macros: asl, lsl, and mov. The ppc port has
324 a more general facility for dealing with macros which could be used if
327 /* These tables can't be `const' because members `next_asm' and `next_dis' are
328 computed at run-time. We could split this into two, as that would put the
329 constant stuff into a readonly section. */
331 struct txvu_opcode txvu_upper_opcodes
[] =
333 /* Macros appear first, so the disassembler will try them first. */
334 /* ??? Any aliases? */
335 /* ??? When close to being finished, clean up by aligning fields. */
337 /* The rest of these needn't be sorted, but it helps to find them if they are. */
338 { "abs", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x1fd) },
339 { "add", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x28) },
340 { "addi", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x22) },
341 { "addq", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x20) },
342 { "add", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ VUOP4 (~0), VUOP4 (0) },
343 { "adda", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP11
, VUOP11 (0x2bc) },
344 { "addai", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x23e) },
345 { "addaq", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x23c) },
346 { "adda", { UBC
, DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP9
, VUOP9 (0xf) },
347 { "clip", { DOTDEST
, SP
, VFSREG
}, MURES
+ MDEST
+ MT
+ MUOP11
, VDEST (0xf) + VUOP11 (0x1ff) },
348 { "ftoi0", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x17c) },
349 { "ftoi4", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x17d) },
350 { "ftoi12", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x17e) },
351 { "ftoi15", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x17f) },
352 { "itof0", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x13c) },
353 { "itof4", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x13d) },
354 { "itof12", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x13e) },
355 { "itof15", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MURES
+ MUOP11
, VUOP11 (0x13f) },
356 { "madd", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x29) },
357 { "maddi", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x23) },
358 { "maddq", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x21) },
359 { "madd", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP4
, VUOP4 (0x2) },
360 { "madda", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP11
, VUOP11 (0x2bd) },
361 { "maddai", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x23f) },
362 { "maddaq", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x23d) },
363 { "madda", { UBC
, DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP9
, VUOP9 (0x2f) },
364 { "max", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x2b) },
365 { "maxi", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x2d) },
366 { "max", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP4
, VUOP4 (0x4) },
367 /* ??? mini or min? */
368 { "mini", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x2f) },
369 { "minii", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x1f) },
370 { "mini", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP4
, VUOP4 (0x5) },
371 { "msub", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x2d) },
372 { "msubi", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x27) },
373 { "msubq", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x25) },
374 { "msub", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP4
, VUOP4 (0x3) },
375 { "msuba", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP11
, VUOP11 (0x2fd) },
376 { "msubai", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x27f) },
377 { "msubaq", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x27d) },
378 { "msuba", { UBC
, DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP9
, VUOP9 (0x3f) },
379 { "mul", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x2a) },
380 { "muli", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x1e) },
381 { "mulq", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x1c) },
382 { "mul", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ VUOP4 (~0), VUOP4 (6) },
383 { "mula", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP11
, VUOP11 (0x2be) },
384 { "mulai", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x1fe) },
385 { "mulaq", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x1fc) },
386 { "mula", { UBC
, DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP9
, VUOP9 (0x6f) },
387 { "nop", { 0 }, MURES
+ MDEST
+ MT
+ MS
+ MUOP11
, VUOP11 (0x2ff) },
388 { "opmula", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
, UXYZ
}, MURES
+ MUOP11
, VUOP11 (0x2fe) },
389 { "opmsub", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
, UXYZ
}, MURES
+ MUOP6
, VUOP6 (0x2e) },
390 { "sub", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP6
, VUOP6 (0x2c) },
391 { "subi", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x26) },
392 { "subq", { DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP6
, VUOP6 (0x24) },
393 { "sub", { UBC
, DOTDEST
, SP
, VFDREG
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ VUOP4 (~0), VUOP4 (1) },
394 { "suba", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, VFTREG
}, MURES
+ MUOP11
, VUOP11 (0x2fc) },
395 { "subai", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, I
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x27e) },
396 { "subaq", { DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, Q
}, MURES
+ MT
+ MUOP11
, VUOP11 (0x27c) },
397 { "suba", { UBC
, DOTDEST
, SP
, UACCDEST
, C
, VFSREG
, C
, UBCFTREG
}, MURES
+ MUOP9
, VUOP9 (0x1f) }
399 const int txvu_upper_opcodes_count
= sizeof (txvu_upper_opcodes
) / sizeof (txvu_upper_opcodes
[0]);
401 /* Lower instruction Value macros. */
404 #define VLOP6(x) V ((x), 6, 0)
406 #define VLOP7(x) V ((x), 7, 25)
408 #define VLOP11(x) V ((x), 11, 0)
409 /* 11 bit immediate. */
410 #define VLIMM11(x) V ((x), 11, 0)
412 #define VLFTF(x) V ((x), 2, 23)
414 #define VLFSF(x) V ((x), 2, 21)
415 /* Upper bit of 12 bit unsigned immediate. */
416 #define VLUIMM12TOP(x) V ((x), 1, 21)
417 /* Upper 4 bits of 15 bit unsigned immediate. */
418 #define VLUIMM15TOP(x) VDEST (x)
420 /* Lower instruction field masks. */
421 #define MLOP6 VLOP6 (~0)
422 #define MLOP7 VLOP7 (~0)
423 #define MLOP11 VLOP11 (~0)
424 #define MLIMM11 VLIMM11 (~0)
425 #define MLB24 V (1, 1, 24)
426 #define MLUIMM12TOP VLUIMM12TOP (~0)
427 /* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits.
428 The upper 1 bit is part of the `dest' field. This mask is for the
429 other 3 bits of the dest field. */
430 #define MLUIMM12UNUSED V (7, 3, 22)
431 #define MLUIMM15TOP MDEST
433 struct txvu_opcode txvu_lower_opcodes
[] =
435 /* Macros appear first, so the disassembler will try them first. */
436 /* ??? Any aliases? */
437 /* ??? There isn't an explicit nop. Apparently it's "move vf0,vf0". */
438 { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) },
440 /* The rest of these needn't be sorted, but it helps to find them if they are. */
441 { "b", { SP
, LPCREL11
}, MLOP7
+ MDEST
+ MT
+ MS
, VLOP7 (0x20) },
442 { "bal", { SP
, LITREG
, C
, LPCREL11
}, MLOP7
+ MDEST
+ MS
, VLOP7 (0x21) },
443 { "div", { SP
, Q
, C
, LFSFFSREG
, C
, LFTFFTREG
}, MLOP7
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x3bc) },
444 { "eatan", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7fd) },
445 { "eatanxy", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77c) },
446 { "eatanxz", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77d) },
447 { "eexp", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7fe) },
448 { "eleng", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x74e) },
449 { "ercpr", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7be) },
450 { "erleng", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73f) },
451 { "ersadd", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73d) },
452 { "ersqrt", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7bd) },
453 { "esadd", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73c) },
454 { "esin", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7fc) },
455 { "esqrt", { SP
, P
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLOP11
, VLOP7 (0x40) + VLOP11 (0x7bc) },
456 { "esum", { SP
, P
, C
, LFSREG
}, MLOP7
+ MDEST
+ MT
+ MLOP11
, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) },
457 { "fcand", { SP
, LVI01
, C
, LUIMM24
}, MLOP7
+ MLB24
, VLOP7 (0x12) },
458 { "fceq", { SP
, LVI01
, C
, LUIMM24
}, MLOP7
+ MLB24
, VLOP7 (0x10) },
459 { "fcget", { SP
, LITREG
}, MLOP7
+ MDEST
+ MS
+ MLIMM11
, VLOP7 (0x1c) },
460 { "fcor", { SP
, LVI01
, C
, LUIMM24
}, MLOP7
+ MLB24
, VLOP7 (0x13) },
461 { "fcset", { SP
, LUIMM24
}, MLOP7
+ MLB24
, VLOP7 (0x11) },
462 { "fmand", { SP
, LITREG
, C
, LISREG
}, MLOP7
+ MDEST
+ MLIMM11
, VLOP7 (0x1a) },
463 { "fmeq", { SP
, LITREG
, C
, LISREG
}, MLOP7
+ MDEST
+ MLIMM11
, VLOP7 (0x18) },
464 { "fmor", { SP
, LITREG
, C
, LISREG
}, MLOP7
+ MDEST
+ MLIMM11
, VLOP7 (0x1b) },
465 { "fsand", { SP
, LITREG
, C
, LUIMM12
}, MLOP7
+ MLUIMM12UNUSED
+ MS
, VLOP7 (0x16) },
466 { "fseq", { SP
, LITREG
, C
, LUIMM12
}, MLOP7
+ MLUIMM12UNUSED
+ MS
, VLOP7 (0x14) },
467 { "fsor", { SP
, LITREG
, C
, LUIMM12
}, MLOP7
+ MLUIMM12UNUSED
+ MS
, VLOP7 (0x17) },
468 { "fsset", { SP
, LUIMM12UP6
}, MLOP7
+ MLUIMM12UNUSED
+ V (~0, 6, 0) + MS
+ MT
, VLOP7 (0x15) },
469 { "iadd", { SP
, LIDREG
, C
, LISREG
, C
, LITREG
}, MLOP7
+ MDEST
+ MLOP6
, VLOP7 (0x40) + VLOP6 (0x30) },
470 { "iaddi", { SP
, LITREG
, C
, LISREG
, C
, LIMM5
}, MLOP7
+ MDEST
+ MLOP6
, VLOP7 (0x40) + VLOP6 (0x32) },
471 { "iaddiu", { SP
, LITREG
, C
, LISREG
, C
, LUIMM15
}, MLOP7
, VLOP7 (0x08) },
472 { "iand", { SP
, LIDREG
, C
, LISREG
, C
, LITREG
}, MLOP7
+ MDEST
+ MLOP6
, VLOP7 (0x40) + VLOP6 (0x34) },
473 { "ibeq", { SP
, LITREG
, C
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
, VLOP7 (0x28) },
474 { "ibgez", { SP
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
+ MT
, VLOP7 (0x2f) },
475 { "ibgtz", { SP
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
+ MT
, VLOP7 (0x2d) },
476 { "iblez", { SP
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
+ MT
, VLOP7 (0x2e) },
477 { "ibltz", { SP
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
+ MT
, VLOP7 (0x2c) },
478 { "ibne", { SP
, LITREG
, C
, LISREG
, C
, LPCREL11
}, MLOP7
+ MDEST
, VLOP7 (0x29) },
479 { "ilw", { LDOTDEST1
, SP
, LITREG
, C
, LIMM11
, '(', LISREG
, ')', LDEST1
}, MLOP7
, VLOP7 (0x04) },
480 { "ilwr", { LDOTDEST1
, SP
, LITREG
, C
, '(', LISREG
, ')', LDEST1
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3fe) },
481 { "ior", { SP
, LIDREG
, C
, LISREG
, C
, LITREG
}, MLOP7
+ MDEST
+ MLOP6
, VLOP7 (0x40) + VLOP6 (0x35) },
482 { "isub", { SP
, LIDREG
, C
, LISREG
, C
, LITREG
}, MLOP7
+ MDEST
+ MLOP6
, VLOP7 (0x40) + VLOP6 (0x31) },
483 { "isubiu", { SP
, LITREG
, C
, LISREG
, C
, LUIMM15
}, MLOP7
, VLOP7 (0x09) },
484 { "isw", { LDOTDEST1
, SP
, LITREG
, C
, LIMM11
, '(', LISREG
, ')', LDEST1
}, MLOP7
, VLOP7 (0x05) },
485 { "iswr", { LDOTDEST1
, SP
, LITREG
, C
, '(', LISREG
, ')', LDEST1
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3ff) },
486 { "jalr", { SP
, LITREG
, C
, LISREG
}, MLOP7
+ MDEST
+ MLIMM11
, VLOP7 (0x25) },
487 { "jr", { SP
, LISREG
}, MLOP7
+ MDEST
+ MT
+ MLIMM11
, VLOP7 (0x24) },
488 { "lq", { DOTDEST
, SP
, VFTREG
, C
, LIMM11
, '(', LISREG
, ')' }, MLOP7
, VLOP7 (0x00) },
489 { "lqd", { DOTDEST
, SP
, VFTREG
, C
, '(', '-', '-', LISREG
, ')' }, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x37e) },
490 { "lqi", { DOTDEST
, SP
, VFTREG
, C
, '(', LISREG
, '+', '+', ')' }, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x37c) },
491 /* Only a single VF reg is allowed here. We can use VFTREG because LDOTDEST1
492 handles verifying only a single choice of xyzw is present. */
493 { "mfir", { LDOTDEST1
, SP
, VFTREG
, C
, LISREG
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3fc) },
494 { "mfp", { DOTDEST
, SP
, VFTREG
, C
, P
}, MLOP7
+ MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x67c) },
495 { "move", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x33c) },
496 { "mr32", { DOTDEST
, SP
, VFTREG
, C
, VFSREG
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x33d) },
497 { "mtir", { LDOTDEST1
, SP
, LITREG
, C
, VFSREG
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3fd) },
498 { "rget", { DOTDEST
, SP
, VFTREG
, C
, R
}, MLOP7
+ MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x43d) },
499 { "rinit", { SP
, R
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x43e) },
500 { "rnext", { DOTDEST
, SP
, VFTREG
, C
, R
}, MLOP7
+ MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x43c) },
501 { "rsqrt", { SP
, Q
, C
, LFSFFSREG
, C
, LFTFFTREG
}, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3be) },
502 { "rxor", { SP
, R
, C
, LFSFFSREG
}, MLOP7
+ VLFTF (~0) + MT
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x43f) },
503 { "sq", { DOTDEST
, SP
, VFTREG
, C
, LIMM11
, '(', LISREG
, ')' }, MLOP7
, VLOP7 (0x01) },
504 { "sqd", { DOTDEST
, SP
, VFTREG
, C
, '(', '-', '-', LISREG
, ')' }, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x37f) },
505 { "sqi", { DOTDEST
, SP
, VFTREG
, C
, '(', LISREG
, '+', '+', ')' }, MLOP7
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x37d) },
506 { "sqrt", { SP
, Q
, C
, LFTFFTREG
}, MLOP7
+ VLFSF (~0) + MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x3bd) },
507 { "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) },
508 { "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) },
509 { "xgkick", { SP
, LISREG
}, MLOP7
+ MDEST
+ MT
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x6fc) },
510 { "xitop", { SP
, LITREG
}, MLOP7
+ MDEST
+ MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x6bd) },
511 { "xtop", { SP
, LITREG
}, MLOP7
+ MDEST
+ MS
+ MLIMM11
, VLOP7 (0x40) + VLIMM11 (0x6bc) }
513 const int txvu_lower_opcodes_count
= sizeof (txvu_lower_opcodes
) / sizeof (txvu_lower_opcodes
[0]);
515 /* Value of DEST in use.
516 Each of the registers must specify the same value as the opcode.
517 ??? Perhaps remove the duplication? */
518 static int mnemonic_dest
;
520 /* Value of BC to use.
521 The register specified for the ftreg must match the broadcast register
522 specified in the opcode. */
523 static int mnemonic_bc
;
525 /* Multiple destination choice support.
526 The "dest" string selects any combination of x,y,z,w.
527 [The letters are ordered that way to follow the manual's style.] */
529 /* Utility to parse a `dest' spec.
530 Return the found value.
531 *PSTR is set to the character that terminated the parsing.
532 It is up to the caller to do any error checking. */
544 case 'x' : case 'X' : dest
|= TXVU_DEST_X
; break;
545 case 'y' : case 'Y' : dest
|= TXVU_DEST_Y
; break;
546 case 'z' : case 'Z' : dest
|= TXVU_DEST_Z
; break;
547 case 'w' : case 'W' : dest
|= TXVU_DEST_W
; break;
548 default : return dest
;
557 parse_dotdest (pstr
, errmsg
)
565 *errmsg
= "missing `.'";
570 dest
= _parse_dest (pstr
);
571 if (dest
== 0 || isalnum (**pstr
))
573 *errmsg
= "invalid `dest'";
580 /* Parse a `dest' spec where only a single letter is allowed,
581 but the encoding handles all four. */
584 parse_dotdest1 (pstr
, errmsg
)
593 *errmsg
= "missing `.'";
600 case 'x' : case 'X' : dest
= TXVU_DEST_X
; break;
601 case 'y' : case 'Y' : dest
= TXVU_DEST_Y
; break;
602 case 'z' : case 'Z' : dest
= TXVU_DEST_Z
; break;
603 case 'w' : case 'W' : dest
= TXVU_DEST_W
; break;
604 default : *errmsg
= "invalid `dest'"; return 0;
607 c
= tolower (**pstr
);
608 if (c
== 'x' || c
== 'y' || c
== 'z' || c
== 'w')
610 *errmsg
= "only one of x,y,z,w can be specified";
613 if (isalnum (**pstr
))
615 *errmsg
= "invalid `dest'";
622 /* Parse a `dest' spec with no leading '.', where only a single letter is
623 allowed, but the encoding handles all four. The parsed value must match
624 that recorded in `dest'. */
627 parse_dest1 (pstr
, errmsg
)
634 dest
= _parse_dest (pstr
);
635 if (dest
!= TXVU_DEST_X
636 && dest
!= TXVU_DEST_Y
637 && dest
!= TXVU_DEST_Z
638 && dest
!= TXVU_DEST_W
)
640 *errmsg
= "expecting one of x,y,z,w";
644 if (dest
!= mnemonic_dest
)
646 *errmsg
= "`dest' suffix does not match instruction `dest'";
654 insert_dotdest (insn
, operand
, mods
, value
, errmsg
)
656 const struct txvu_operand
*operand
;
661 /* Record the DEST value in use so the register parser can use it. */
662 mnemonic_dest
= value
;
663 *insn
|= value
<< operand
->shift
;
667 extract_dotdest (insn
, operand
, mods
, pinvalid
)
669 const struct txvu_operand
*operand
;
673 /* Record the DEST value in use so the register printer can use it. */
674 mnemonic_dest
= (*insn
>> operand
->shift
) & ((1 << operand
->bits
) - 1);
675 return mnemonic_dest
;
678 /* Utility to print a multiple dest spec. */
681 _print_dest (info
, insn
, value
)
682 disassemble_info
*info
;
686 if (value
& TXVU_DEST_X
)
687 (*info
->fprintf_func
) (info
->stream
, "x");
688 if (value
& TXVU_DEST_Y
)
689 (*info
->fprintf_func
) (info
->stream
, "y");
690 if (value
& TXVU_DEST_Z
)
691 (*info
->fprintf_func
) (info
->stream
, "z");
692 if (value
& TXVU_DEST_W
)
693 (*info
->fprintf_func
) (info
->stream
, "w");
697 print_dotdest (info
, insn
, value
)
698 disassemble_info
*info
;
702 (*info
->fprintf_func
) (info
->stream
, ".");
703 _print_dest (info
, insn
, value
);
707 print_dest1 (info
, insn
, value
)
708 disassemble_info
*info
;
712 _print_dest (info
, insn
, mnemonic_dest
);
715 /* Utilities for single destination choice handling. */
718 _parse_sdest (pstr
, errmsg
)
727 case 'x' : case 'X' : dest
= TXVU_SDEST_X
; break;
728 case 'y' : case 'Y' : dest
= TXVU_SDEST_Y
; break;
729 case 'z' : case 'Z' : dest
= TXVU_SDEST_Z
; break;
730 case 'w' : case 'W' : dest
= TXVU_SDEST_W
; break;
731 default : *errmsg
= "only one of x,y,z,w can be specified"; return 0;
734 c
= tolower (**pstr
);
735 if (c
== 'x' || c
== 'y' || c
== 'z' || c
== 'w')
737 *errmsg
= "only one of x,y,z,w can be specified";
740 if (isalnum (**pstr
))
742 *errmsg
= "invalid `dest'";
750 print_sdest (info
, insn
, value
)
751 disassemble_info
*info
;
759 case TXVU_SDEST_X
: c
= 'x'; break;
760 case TXVU_SDEST_Y
: c
= 'y'; break;
761 case TXVU_SDEST_Z
: c
= 'z'; break;
762 case TXVU_SDEST_W
: c
= 'w'; break;
765 (*info
->fprintf_func
) (info
->stream
, "%c", c
);
768 /* Broadcase field. */
771 parse_bc (pstr
, errmsg
)
775 long value
= _parse_sdest (pstr
, errmsg
);
779 /* Save value for later verification in register parsing. */
784 /* During the extraction process, save the bc field for use in
785 printing the bc register. */
788 extract_bc (insn
, operand
, mods
, pinvalid
)
790 const struct txvu_operand
*operand
;
794 mnemonic_bc
= *insn
& 3;
799 parse_vfreg (pstr
, errmsg
)
808 if (tolower (str
[0]) != 'v'
809 || tolower (str
[1]) != 'f')
811 *errmsg
= "unknown register";
815 /* FIXME: quick hack until the framework works. */
816 start
= str
= str
+ 2;
817 while (*str
&& isdigit (*str
))
820 if (reg
< 0 || reg
> 31)
822 *errmsg
= "invalid register number";
825 reg_dest
= _parse_dest (&str
);
826 if (reg_dest
== 0 || isalnum (*str
))
828 *errmsg
= "invalid `dest'";
831 if (reg_dest
!= mnemonic_dest
)
833 *errmsg
= "register `dest' does not match instruction `dest'";
841 print_vfreg (info
, insn
, value
)
842 disassemble_info
*info
;
846 (*info
->fprintf_func
) (info
->stream
, "vf%02ld", value
);
847 _print_dest (info
, insn
, mnemonic_dest
);
850 /* FT register in broadcast case. */
853 parse_bcftreg (pstr
, errmsg
)
862 if (tolower (str
[0]) != 'v'
863 || tolower (str
[1]) != 'f')
865 *errmsg
= "unknown register";
869 /* FIXME: quick hack until the framework works. */
870 start
= str
= str
+ 2;
871 while (*str
&& isdigit (*str
))
874 if (reg
< 0 || reg
> 31)
876 *errmsg
= "invalid register number";
879 reg_bc
= _parse_sdest (&str
, errmsg
);
882 if (reg_bc
!= mnemonic_bc
)
884 *errmsg
= "register `bc' does not match instruction `bc'";
892 print_bcftreg (info
, insn
, value
)
893 disassemble_info
*info
;
897 (*info
->fprintf_func
) (info
->stream
, "vf%02ld", value
);
898 print_sdest (info
, insn
, mnemonic_bc
);
904 parse_accdest (pstr
, errmsg
)
911 if (strncasecmp (str
, "acc", 3) != 0)
913 *errmsg
= "expecting `acc'";
917 acc_dest
= _parse_dest (&str
);
918 if (acc_dest
== 0 || isalnum (*str
))
920 *errmsg
= "invalid `dest'";
923 if (acc_dest
!= mnemonic_dest
)
925 *errmsg
= "acc `dest' does not match instruction `dest'";
929 /* Value isn't used, but we must return something. */
934 print_accdest (info
, insn
, value
)
935 disassemble_info
*info
;
939 (*info
->fprintf_func
) (info
->stream
, "acc");
940 _print_dest (info
, insn
, mnemonic_dest
);
943 /* XYZ operand handling.
944 This simplifies the opmula,opmsub entries by keeping them equivalent to
948 insert_xyz (insn
, operand
, mods
, value
, errmsg
)
950 const struct txvu_operand
*operand
;
955 if (mnemonic_dest
!= (TXVU_DEST_X
| TXVU_DEST_Y
| TXVU_DEST_Z
))
956 *errmsg
= "expecting `xyz' for `dest' value";
959 /* F[ST] register using selector in F[ST]F field.
960 Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator
961 followed by the 5 bit register number. */
964 parse_ffstreg (pstr
, errmsg
)
972 if (tolower (str
[0]) != 'v'
973 || tolower (str
[1]) != 'f')
975 *errmsg
= "unknown register";
979 /* FIXME: quick hack until the framework works. */
980 start
= str
= str
+ 2;
981 while (*str
&& isdigit (*str
))
984 if (reg
< 0 || reg
> 31)
986 *errmsg
= "invalid register number";
989 xyzw
= _parse_sdest (&str
, errmsg
);
993 return reg
| (xyzw
<< 5);
997 print_ffstreg (info
, insn
, value
)
998 disassemble_info
*info
;
1002 (*info
->fprintf_func
) (info
->stream
, "vf%02ld", value
& TXVU_MASK_REG
);
1003 print_sdest (info
, insn
, (value
>> 5) & 3);
1007 insert_ffstreg (insn
, operand
, mods
, value
, errmsg
)
1009 const struct txvu_operand
*operand
;
1012 const char **errmsg
;
1014 if (operand
->shift
== TXVU_SHIFT_SREG
)
1015 *insn
|= VLFSF (value
>> 5) | VS (value
);
1017 *insn
|= VLFTF (value
>> 5) | VT (value
);
1021 extract_ffstreg (insn
, operand
, mods
, pinvalid
)
1023 const struct txvu_operand
*operand
;
1027 if (operand
->shift
== TXVU_SHIFT_SREG
)
1028 return (((*insn
& VLFSF (~0)) >> 21) << 5) | VS (*insn
);
1030 return (((*insn
& VLFTF (~0)) >> 21) << 5) | VT (*insn
);
1036 parse_freg (pstr
, errmsg
)
1038 const char **errmsg
;
1044 if (tolower (str
[0]) != 'v'
1045 || tolower (str
[1]) != 'f')
1047 *errmsg
= "unknown register";
1051 /* FIXME: quick hack until the framework works. */
1052 start
= str
= str
+ 2;
1053 while (*str
&& isdigit (*str
))
1056 if (reg
< 0 || reg
> 31)
1058 *errmsg
= "invalid register number";
1066 print_freg (info
, insn
, value
)
1067 disassemble_info
*info
;
1071 (*info
->fprintf_func
) (info
->stream
, "vf%02ld", value
);
1077 parse_ireg (pstr
, errmsg
)
1079 const char **errmsg
;
1085 if (tolower (str
[0]) != 'v'
1086 || tolower (str
[1]) != 'i')
1088 *errmsg
= "unknown register";
1092 /* FIXME: quick hack until the framework works. */
1093 start
= str
= str
+ 2;
1094 while (*str
&& isdigit (*str
))
1097 if (reg
< 0 || reg
> 31)
1099 *errmsg
= "invalid register number";
1107 print_ireg (info
, insn
, value
)
1108 disassemble_info
*info
;
1112 (*info
->fprintf_func
) (info
->stream
, "vi%02ld", value
);
1115 /* VI01 register. */
1118 parse_vi01 (pstr
, errmsg
)
1120 const char **errmsg
;
1126 if (tolower (str
[0]) != 'v'
1127 || tolower (str
[1]) != 'i')
1129 *errmsg
= "unknown register";
1133 /* FIXME: quick hack until the framework works. */
1134 start
= str
= str
+ 2;
1135 while (*str
&& isdigit (*str
))
1140 *errmsg
= "vi01 required here";
1148 print_vi01 (info
, insn
, value
)
1149 disassemble_info
*info
;
1153 (*info
->fprintf_func
) (info
->stream
, "vi01");
1156 /* Lower instruction 12 bit unsigned immediate. */
1159 insert_luimm12 (insn
, operand
, mods
, value
, errmsg
)
1161 const struct txvu_operand
*operand
;
1164 const char **errmsg
;
1166 *insn
|= VLUIMM12TOP ((value
& (1 << 11)) != 0) | VLIMM11 (value
);
1170 extract_luimm12 (insn
, operand
, mods
, pinvalid
)
1172 const struct txvu_operand
*operand
;
1176 return (((*insn
& MLUIMM12TOP
) != 0) << 11) | VLIMM11 (*insn
);
1179 /* Lower instruction 12 bit unsigned immediate, upper 6 bits. */
1182 insert_luimm12up6 (insn
, operand
, mods
, value
, errmsg
)
1184 const struct txvu_operand
*operand
;
1187 const char **errmsg
;
1189 *insn
|= VLUIMM12TOP ((value
& (1 << 11)) != 0) | (value
& 0x7c0);
1192 /* Lower instruction 15 bit unsigned immediate. */
1195 insert_luimm15 (insn
, operand
, mods
, value
, errmsg
)
1197 const struct txvu_operand
*operand
;
1200 const char **errmsg
;
1202 *insn
|= VLUIMM15TOP (value
>> 11) | VLIMM11 (value
);
1206 extract_luimm15 (insn
, operand
, mods
, pinvalid
)
1208 const struct txvu_operand
*operand
;
1212 return (((*insn
& MLUIMM15TOP
) >> 21) << 11) | VLIMM11 (*insn
);
1217 PARSE_FN (pke_ibit
);
1218 PRINT_FN (pke_ibit
);
1220 PARSE_FN (pke_mode
);
1221 PRINT_FN (pke_mode
);
1223 PARSE_FN (pke_ability
);
1224 PRINT_FN (pke_ability
);
1226 PARSE_FN (pke_mpgaddr
);
1228 PARSE_FN (pke_varlendata
);
1230 PARSE_FN (pke_imrbits
);
1231 PRINT_FN (pke_imrbits
);
1233 PARSE_FN (pke_unpacktype
);
1234 PRINT_FN (pke_unpacktype
);
1236 PARSE_FN (pke_unpackaddr
);
1238 const struct txvu_operand pke_operands
[] =
1240 /* place holder (??? not sure if needed) */
1241 #define PKE_UNUSED 128
1245 #define PKE_IBIT (PKE_UNUSED + 1)
1246 { 1, 31, TXVU_OPERAND_SUFFIX
, parse_pke_ibit
, 0, 0, print_pke_ibit
},
1248 /* An 8 bit unsigned immediate, stored in upper 8 bits of immed field. */
1249 #define PKE_UIMM8UP (PKE_IBIT + 1)
1250 { 8, 8, 0, 0, 0, 0, 0 },
1252 /* An 8 bit unsigned immediate, stored in lower 8 bits of immed field. */
1253 #define PKE_UIMM8LO (PKE_UIMM8UP + 1)
1254 { 8, 0, 0, 0, 0, 0, 0 },
1256 /* An 16 bit unsigned immediate, stored in lower 8 bits of immed field. */
1257 #define PKE_UIMM16 (PKE_UIMM8LO + 1)
1258 { 16, 0, 0, 0, 0, 0, 0 },
1260 /* The mode operand of `stmod'. */
1261 #define PKE_MODE (PKE_UIMM16 + 1)
1262 { 2, 0, 0, parse_pke_mode
, 0, 0, print_pke_mode
},
1264 /* The ability operand of `mskpath3'. */
1265 #define PKE_ABILITY (PKE_MODE + 1)
1266 { 1, 15, 0, parse_pke_ability
, 0, 0, print_pke_ability
},
1269 #define PKE_VUADDR (PKE_ABILITY + 1)
1270 { 16, 0, 0, 0, 0, 0, 0 },
1272 /* A 32 bit immediate, appearing in 2nd,3rd,4th,5th words. */
1273 #define PKE_UIMM32 (PKE_VUADDR + 1)
1274 { 32, 0, 0, 0, 0, 0, 0 },
1276 /* VU address used by mpg insn. */
1277 #define PKE_MPGADDR (PKE_UIMM32 + 1)
1278 { 16, 0, TXVU_OPERAND_ADDRESS
, parse_pke_mpgaddr
, 0, 0, 0 },
1280 /* A variable length data specifier.
1281 Any of: file name, number, or '*'. */
1282 #define PKE_VARLENDATA (PKE_MPGADDR + 1)
1283 { 0, 0, 0, parse_pke_varlendata
, 0, 0, 0 },
1285 /* The IMR bits of the unpack insn. */
1286 #define PKE_IMRBITS (PKE_VARLENDATA + 1)
1287 { 0, 0, TXVU_OPERAND_SUFFIX
, parse_pke_imrbits
, 0, 0, print_pke_imrbits
},
1289 /* The type of the unpack insn. */
1290 #define PKE_UNPACKTYPE (PKE_IMRBITS + 1)
1291 { 4, 24, 0, parse_pke_unpacktype
, 0, 0, print_pke_unpacktype
},
1293 /* VU address used by unpack insn. */
1294 #define PKE_UNPACKADDR (PKE_UIMM32 + 1)
1295 { 16, 0, TXVU_OPERAND_ADDRESS
, parse_pke_unpackaddr
, 0, 0, 0 },
1297 /* end of list place holder */
1301 /* Field mask values. */
1302 #define MPKECMD 0x7f000000
1303 #define MPKEUNPACK 0x60000000
1306 #define VPKECMD(x) V ((x), 7, 24)
1307 #define VPKEUNPACK V (0x60, 8, 24)
1309 struct txvu_opcode pke_opcodes
[] =
1311 { "pkenop", { PKE_IBIT
}, 0x7fffffff, 0 },
1312 { "stcycle", { PKE_IBIT
, SP
, PKE_UIMM8UP
, C
, PKE_UIMM8LO
}, MPKECMD
, VPKECMD (1) },
1313 { "offset", { PKE_IBIT
, SP
, PKE_UIMM16
}, MPKECMD
, VPKECMD (2) },
1314 { "base", { PKE_IBIT
, SP
, PKE_UIMM16
}, MPKECMD
, VPKECMD (3) },
1315 { "itop", { PKE_IBIT
, SP
, PKE_UIMM16
}, MPKECMD
, VPKECMD (4) },
1316 { "stmod", { PKE_IBIT
, SP
, PKE_MODE
}, MPKECMD
+ V (~0, 14, 2), VPKECMD (5) },
1317 { "mskpath3", { PKE_IBIT
, SP
, PKE_ABILITY
}, MPKECMD
+ V (~0, 15, 0), VPKECMD (6) },
1318 { "pkemark", { PKE_IBIT
, SP
, PKE_UIMM16
}, MPKECMD
, VPKECMD (7) },
1319 { "flushe", { PKE_IBIT
}, MPKECMD
, VPKECMD (16) },
1320 { "flush", { PKE_IBIT
}, MPKECMD
, VPKECMD (17) },
1321 { "flusha", { PKE_IBIT
}, MPKECMD
, VPKECMD (19) },
1322 { "pkemscal", { PKE_IBIT
, SP
, PKE_VUADDR
}, MPKECMD
, VPKECMD (20) },
1323 { "pkemscnt", { PKE_IBIT
}, MPKECMD
, VPKECMD (23) },
1324 { "pkemscalf", { PKE_IBIT
, SP
, PKE_VUADDR
}, MPKECMD
, VPKECMD (21) },
1326 /* 2 word instructions */
1327 { "stmask", { PKE_IBIT
, SP
, PKE_UIMM32
}, MPKECMD
, VPKECMD (32), PKE_OPCODE_LEN2
},
1329 /* 5 word instructions */
1330 { "strow", { PKE_IBIT
, SP
, PKE_UIMM32
, C
, PKE_UIMM32
, C
, PKE_UIMM32
, C
, PKE_UIMM32
}, MPKECMD
, VPKECMD (48), PKE_OPCODE_LEN5
},
1331 { "stcol", { PKE_IBIT
, SP
, PKE_UIMM32
, C
, PKE_UIMM32
, C
, PKE_UIMM32
, C
, PKE_UIMM32
}, MPKECMD
, VPKECMD (49), PKE_OPCODE_LEN5
},
1333 /* variable length instructions */
1334 { "mpg", { PKE_IBIT
, SP
, PKE_MPGADDR
, PKE_VARLENDATA
}, MPKECMD
, VPKECMD (0x4a), PKE_OPCODE_LENVAR
+ PKE_OPCODE_MPG
},
1335 { "direct", { PKE_IBIT
, SP
, PKE_VARLENDATA
}, MPKECMD
, VPKECMD (0x50), PKE_OPCODE_LENVAR
+ PKE_OPCODE_DIRECT
},
1336 { "directhl", { PKE_IBIT
, SP
, PKE_VARLENDATA
}, MPKECMD
, VPKECMD (0x51), PKE_OPCODE_LENVAR
+ PKE_OPCODE_DIRECT
},
1337 { "unpack", { PKE_IMRBITS
, SP
, PKE_UNPACKTYPE
, C
, PKE_UNPACKADDR
, C
, PKE_VARLENDATA
}, MPKEUNPACK
, VPKEUNPACK
, PKE_OPCODE_LENVAR
+ PKE_OPCODE_UNPACK
},
1339 const int pke_opcodes_count
= sizeof (pke_opcodes
) / sizeof (pke_opcodes
[0]);
1341 /* PKE parse,insert,extract,print helper fns. */
1344 parse_pke_ibit (pstr
, errmsg
)
1346 const char **errmsg
;
1354 for (str
= str
+ 1; *str
!= ']'; ++str
)
1356 switch (tolower (*str
))
1358 case 'i' : flags
= 1; break;
1359 default : *errmsg
= "unknown flag"; return 0;
1368 print_pke_ibit (info
, insn
, value
)
1369 disassemble_info
*info
;
1373 (*info
->fprintf_func
) (info
->stream
, "???");
1376 static const keyword stmod_modes
[] = {
1377 { PKE_MODE_DIRECT
, "direct" },
1378 { PKE_MODE_ADD
, "add" },
1379 { PKE_MODE_ADDROW
, "addrow" },
1384 parse_pke_mode (pstr
, errmsg
)
1386 const char **errmsg
;
1394 str
= scan_symbol (str
);
1397 mode
= lookup_keyword_value (stmod_modes
, start
, 0);
1404 *errmsg
= "invalid mode";
1409 print_pke_mode (info
, insn
, value
)
1410 disassemble_info
*info
;
1414 (*info
->fprintf_func
) (info
->stream
, "???");
1418 parse_pke_ability (pstr
, errmsg
)
1420 const char **errmsg
;
1424 if (strncasecmp (str
, "disable", 7) == 0)
1429 else if (strncasecmp (str
, "enable", 6) == 0)
1434 *errmsg
= "invalid ability";
1439 print_pke_ability (info
, insn
, value
)
1440 disassemble_info
*info
;
1444 (*info
->fprintf_func
) (info
->stream
, "???");
1448 parse_pke_mpgaddr (pstr
, errmsg
)
1450 const char **errmsg
;
1458 return 0; /* FIXME:indicate * somehow */
1462 str
= strchr (str
, ',');
1465 *errmsg
= "invalid mpg address";
1469 /* FIXME: call back to expression() to parse address. */
1475 /* The result here is either the length specified,
1476 or PKE_VARLENDATA_FILE or PKE_VARLENDATA_UNKNOWN. */
1479 parse_pke_varlendata (pstr
, errmsg
)
1481 const char **errmsg
;
1489 return 0; /* FIXME:indicate * somehow */
1494 /* FIXME: call back to expression() to parse address,
1495 and pick out filename if such. */
1497 *pstr
= str
+ strlen (str
);
1502 parse_pke_imrbits (pstr
, errmsg
)
1504 const char **errmsg
;
1512 for (str
= str
+ 1; *str
!= ']'; ++str
)
1514 switch (tolower (*str
))
1516 case 'i' : flags
|= PKE_FLAG_I
; break;
1517 case 'm' : flags
|= PKE_FLAG_M
; break;
1518 case 'r' : flags
|= PKE_FLAG_R
; break;
1519 default : *errmsg
= "unknown pke flag"; return 0;
1528 print_pke_imrbits (info
, insn
, value
)
1529 disassemble_info
*info
;
1533 (*info
->fprintf_func
) (info
->stream
, "???");
1536 static const keyword unpack_types
[] = {
1537 { PKE_UNPACK_S_32
, "s_32" },
1538 { PKE_UNPACK_S_16
, "s_16" },
1539 { PKE_UNPACK_S_8
, "s_8" },
1540 { PKE_UNPACK_V2_32
, "v2_32" },
1541 { PKE_UNPACK_V2_16
, "v2_16" },
1542 { PKE_UNPACK_V2_8
, "v2_8" },
1543 { PKE_UNPACK_V3_32
, "v3_32" },
1544 { PKE_UNPACK_V3_16
, "v3_16" },
1545 { PKE_UNPACK_V3_8
, "v3_8" },
1546 { PKE_UNPACK_V4_32
, "v4_32" },
1547 { PKE_UNPACK_V4_16
, "v4_16" },
1548 { PKE_UNPACK_V4_8
, "v4_8" },
1549 { PKE_UNPACK_V4_5
, "v4_5" },
1554 parse_pke_unpacktype (pstr
, errmsg
)
1556 const char **errmsg
;
1564 str
= scan_symbol (str
);
1567 type
= lookup_keyword_value (unpack_types
, start
, 0);
1574 *errmsg
= "invalid unpack type";
1579 print_pke_unpacktype (info
, insn
, value
)
1580 disassemble_info
*info
;
1584 (*info
->fprintf_func
) (info
->stream
, "???");
1588 parse_pke_unpackaddr (pstr
, errmsg
)
1590 const char **errmsg
;
1596 PARSE_FN (dma_flags
);
1597 INSERT_FN (dma_flags
);
1598 EXTRACT_FN (dma_flags
);
1599 PRINT_FN (dma_flags
);
1601 PARSE_FN (dma_data
);
1602 INSERT_FN (dma_data
);
1603 EXTRACT_FN (dma_data
);
1604 PRINT_FN (dma_data
);
1606 PARSE_FN (dma_next
);
1607 INSERT_FN (dma_next
);
1608 EXTRACT_FN (dma_next
);
1609 PRINT_FN (dma_next
);
1611 const struct txvu_operand dma_operands
[] =
1613 /* place holder (??? not sure if needed) */
1614 #define DMA_UNUSED 128
1617 /* dma tag flag bits */
1618 #define DMA_FLAGS (DMA_UNUSED + 1)
1619 { 0, 0, TXVU_OPERAND_SUFFIX
,
1620 parse_dma_flags
, insert_dma_flags
, extract_dma_flags
, print_dma_flags
},
1623 #define DMA_DATA (DMA_FLAGS + 1)
1625 parse_dma_data
, insert_dma_data
, extract_dma_data
, print_dma_data
},
1627 /* dma next tag spec */
1628 #define DMA_NEXT (DMA_DATA + 1)
1630 parse_dma_next
, insert_dma_next
, extract_dma_next
, print_dma_next
},
1632 /* end of list place holder */
1636 struct txvu_opcode dma_opcodes
[] =
1638 /* ??? Some of these may take optional arguments.
1639 The way to handle that is to have multiple table entries, those with and
1640 those without the optional arguments. */
1641 { "dmacnt", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 1 },
1642 { "dmanext", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 2 },
1643 { "dmaref", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 3 },
1644 { "dmarefs", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 4 },
1645 { "dmacall", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 5 },
1646 { "dmaret", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 6 },
1647 { "dmaend", { DMA_FLAGS
, SP
, DMA_DATA
, C
, DMA_NEXT
}, 0, 7 }
1649 const int dma_opcodes_count
= sizeof (dma_opcodes
) / sizeof (dma_opcodes
[0]);
1651 /* DMA parse,insert,extract,print helper fns. */
1654 parse_dma_flags (pstr
, errmsg
)
1656 const char **errmsg
;
1664 for (str
= str
+ 1; *str
!= ']'; ++str
)
1666 switch (tolower (*str
))
1668 case '0' : flags
|= DMA_FLAG_PCE0
; break;
1669 case '1' : flags
|= DMA_FLAG_PCE1
; break;
1670 case 'i' : flags
|= DMA_FLAG_INT
; break;
1671 case 's' : flags
|= DMA_FLAG_SPR
; break;
1672 default : *errmsg
= "unknown dma flag"; return 0;
1681 insert_dma_flags (insn
, operand
, mods
, value
, errmsg
)
1683 const struct txvu_operand
*operand
;
1686 const char **errmsg
;
1691 extract_dma_flags (insn
, operand
, mods
, pinvalid
)
1693 const struct txvu_operand
*operand
;
1701 print_dma_flags (info
, insn
, value
)
1702 disassemble_info
*info
;
1708 (*info
->fprintf_func
) (info
->stream
, "[");
1709 if (value
& DMA_FLAG_PCE0
)
1710 (*info
->fprintf_func
) (info
->stream
, "0");
1711 if (value
& DMA_FLAG_PCE1
)
1712 (*info
->fprintf_func
) (info
->stream
, "1");
1713 if (value
& DMA_FLAG_INT
)
1714 (*info
->fprintf_func
) (info
->stream
, "i");
1715 if (value
& DMA_FLAG_SPR
)
1716 (*info
->fprintf_func
) (info
->stream
, "s");
1717 (*info
->fprintf_func
) (info
->stream
, "]");
1721 /* Parse a DMA data spec which can be either of '*' or a quad word count. */
1724 parse_dma_data (pstr
, errmsg
)
1726 const char **errmsg
;
1734 /* -1 is a special marker to caller to tell it the count is to be
1735 computed from the data. */
1742 while (*str
&& *str
!= ',')
1746 *errmsg
= "invalid dma count";
1749 count
= atoi (start
);
1754 *errmsg
= "invalid dma count";
1759 insert_dma_data (insn
, operand
, mods
, value
, errmsg
)
1761 const struct txvu_operand
*operand
;
1764 const char **errmsg
;
1769 extract_dma_data (insn
, operand
, mods
, pinvalid
)
1771 const struct txvu_operand
*operand
;
1779 print_dma_data (info
, insn
, value
)
1780 disassemble_info
*info
;
1784 (*info
->fprintf_func
) (info
->stream
, "???");
1788 parse_dma_next (pstr
, errmsg
)
1790 const char **errmsg
;
1792 char *start
= *pstr
;
1793 char *end
= scan_symbol (start
);
1797 *errmsg
= "invalid dma next tag";
1800 /* FIXME: unfinished */
1806 insert_dma_next (insn
, operand
, mods
, value
, errmsg
)
1808 const struct txvu_operand
*operand
;
1811 const char **errmsg
;
1816 extract_dma_next (insn
, operand
, mods
, pinvalid
)
1818 const struct txvu_operand
*operand
;
1826 print_dma_next (info
, insn
, value
)
1827 disassemble_info
*info
;
1831 (*info
->fprintf_func
) (info
->stream
, "???");
1834 /* GPUIF support. */
1836 PARSE_FN (gpuif_prim
);
1837 INSERT_FN (gpuif_prim
);
1838 EXTRACT_FN (gpuif_prim
);
1839 PRINT_FN (gpuif_prim
);
1841 PARSE_FN (gpuif_regs
);
1842 INSERT_FN (gpuif_regs
);
1843 EXTRACT_FN (gpuif_regs
);
1844 PRINT_FN (gpuif_regs
);
1846 PARSE_FN (gpuif_nloop
);
1847 INSERT_FN (gpuif_nloop
);
1848 EXTRACT_FN (gpuif_nloop
);
1849 PRINT_FN (gpuif_nloop
);
1851 PARSE_FN (gpuif_eop
);
1852 INSERT_FN (gpuif_eop
);
1853 EXTRACT_FN (gpuif_eop
);
1854 PRINT_FN (gpuif_eop
);
1856 const struct txvu_operand gpuif_operands
[] =
1858 /* place holder (??? not sure if needed) */
1859 #define GPUIF_UNUSED 128
1862 /* PRIM=foo operand */
1863 #define GPUIF_PRIM (GPUIF_UNUSED + 1)
1864 { 0, 0, 0, parse_gpuif_prim
, insert_gpuif_prim
, extract_gpuif_prim
, print_gpuif_prim
},
1866 /* REGS=foo operand */
1867 #define GPUIF_REGS (GPUIF_PRIM + 1)
1868 { 0, 0, 0, parse_gpuif_regs
, insert_gpuif_regs
, extract_gpuif_regs
, print_gpuif_regs
},
1870 /* NLOOP=foo operand */
1871 #define GPUIF_NLOOP (GPUIF_REGS + 1)
1872 { 0, 0, 0, parse_gpuif_nloop
, insert_gpuif_nloop
, extract_gpuif_nloop
, print_gpuif_nloop
},
1875 #define GPUIF_EOP (GPUIF_NLOOP + 1)
1876 { 0, 0, 0, parse_gpuif_eop
, insert_gpuif_eop
, extract_gpuif_eop
, print_gpuif_eop
},
1878 /* end of list place holder */
1882 struct txvu_opcode gpuif_opcodes
[] =
1884 /* Some of these may take optional arguments.
1885 The way this is handled is to have multiple table entries, those with and
1886 those without the optional arguments.
1887 !!! The order here is important. The code that scans this table assumes
1888 that if it reaches the end of a syntax string there is nothing more to
1889 parse. This means that longer versions of instructions must appear before
1890 shorter ones. Otherwise the text at the "end" of a longer one may be
1891 interpreted as junk when the parser is using a shorter version of the
1894 { "gpuifpacked", { SP
, GPUIF_PRIM
, C
, GPUIF_REGS
, C
, GPUIF_NLOOP
, C
, GPUIF_EOP
}, 0, 1 },
1895 { "gpuifpacked", { SP
, GPUIF_REGS
, C
, GPUIF_NLOOP
, C
, GPUIF_EOP
}, 0, 1 },
1896 { "gpuifpacked", { SP
, GPUIF_PRIM
, C
, GPUIF_REGS
, C
, GPUIF_EOP
}, 0, 1 },
1897 { "gpuifpacked", { SP
, GPUIF_PRIM
, C
, GPUIF_REGS
, C
, GPUIF_NLOOP
}, 0, 1 },
1898 { "gpuifpacked", { SP
, GPUIF_REGS
, C
, GPUIF_EOP
}, 0, 1 },
1899 { "gpuifpacked", { SP
, GPUIF_REGS
, C
, GPUIF_NLOOP
}, 0, 1 },
1900 { "gpuifpacked", { SP
, GPUIF_PRIM
, C
, GPUIF_REGS
}, 0, 1 },
1901 { "gpuifpacked", { SP
, GPUIF_REGS
}, 0, 1 },
1903 { "gpuifreglist", { SP
, GPUIF_REGS
, C
, GPUIF_NLOOP
, C
, GPUIF_EOP
}, 0, 2 },
1904 { "gpuifreglist", { SP
, GPUIF_REGS
, C
, GPUIF_EOP
}, 0, 2 },
1905 { "gpuifreglist", { SP
, GPUIF_REGS
, C
, GPUIF_NLOOP
}, 0, 2 },
1906 { "gpuifreglist", { SP
, GPUIF_REGS
}, 0, 2 },
1908 { "gpuifimage", { SP
, GPUIF_NLOOP
}, 0, 3 },
1909 { "gpuifimage", { 0 }, 0, 3 },
1911 const int gpuif_opcodes_count
= sizeof (gpuif_opcodes
) / sizeof (gpuif_opcodes
[0]);
1913 /* GPUIF parse,insert,extract,print helper fns. */
1916 parse_gpuif_prim (pstr
, errmsg
)
1918 const char **errmsg
;
1924 if (strncasecmp (str
, "prim=", 5) != 0)
1926 *errmsg
= "missing PRIM spec";
1930 for (start
= str
; isalnum (*str
); ++str
)
1934 *errmsg
= "missing PRIM spec";
1937 /* FIXME: Yes, atoi doesn't do error checking. Later. */
1938 prim
= atoi (start
);
1944 insert_gpuif_prim (insn
, operand
, mods
, value
, errmsg
)
1946 const struct txvu_operand
*operand
;
1949 const char **errmsg
;
1954 extract_gpuif_prim (insn
, operand
, mods
, pinvalid
)
1956 const struct txvu_operand
*operand
;
1964 print_gpuif_prim (info
, insn
, value
)
1965 disassemble_info
*info
;
1969 (*info
->fprintf_func
) (info
->stream
, "???");
1972 static const keyword gpuif_regs
[] = {
1973 { GPUIF_REG_PRIM
, "prim" },
1974 { GPUIF_REG_RGBAQ
, "rgbaq" },
1975 { GPUIF_REG_ST
, "st" },
1976 { GPUIF_REG_UV
, "uv" },
1977 { GPUIF_REG_XYZF2
, "xyzf2" },
1978 { GPUIF_REG_TEXCLUT_1
, "texclut_1" },
1979 { GPUIF_REG_TEXCLUT_2
, "texclut_2" },
1980 { GPUIF_REG_TEX0_1
, "tex0_1" },
1981 { GPUIF_REG_TEX0_2
, "tex0_2" },
1982 { GPUIF_REG_TEX1_1
, "tex1_1" },
1983 { GPUIF_REG_TEX1_2
, "tex1_2" },
1984 { GPUIF_REG_XYZF3
, "xyzf3" },
1985 { GPUIF_REG_PRMODE
, "prmode" },
1986 { GPUIF_REG_A_D
, "a_d" },
1987 { GPUIF_REG_NOP
, "nop" },
1991 /* Parse a REGS= spec.
1992 The result is ???. */
1995 parse_gpuif_regs (pstr
, errmsg
)
1997 const char **errmsg
;
2004 if (strncasecmp (str
, "regs=", 5) != 0)
2006 *errmsg
= "missing REGS spec";
2013 *errmsg
= "missing '{' in REGS spec";
2018 while (*str
&& *str
!= '}')
2020 /* Pick out the register name. */
2024 str
= scan_symbol (str
);
2027 *errmsg
= "invalid REG";
2031 /* Look it up in the table. */
2035 reg
= lookup_keyword_value (gpuif_regs
, start
, 0);
2039 *errmsg
= "invalid REG";
2043 /* FIXME: save `reg' away somewhere */
2045 /* Prepare for the next one. */
2050 else if (*str
!= '}')
2055 *errmsg
= "missing '{' in REGS spec";
2060 return 0; /* FIXME */
2064 insert_gpuif_regs (insn
, operand
, mods
, value
, errmsg
)
2066 const struct txvu_operand
*operand
;
2069 const char **errmsg
;
2074 extract_gpuif_regs (insn
, operand
, mods
, pinvalid
)
2076 const struct txvu_operand
*operand
;
2084 print_gpuif_regs (info
, insn
, value
)
2085 disassemble_info
*info
;
2089 (*info
->fprintf_func
) (info
->stream
, "???");
2093 parse_gpuif_nloop (pstr
, errmsg
)
2095 const char **errmsg
;
2102 if (strncasecmp (str
, "nloop=", 6) != 0)
2104 *errmsg
= "missing NLOOP spec";
2110 str
= scan_symbol (str
);
2113 *errmsg
= "invalid NOOP spec";
2116 /* FIXME: error checking */
2117 nloop
= atoi (start
);
2123 insert_gpuif_nloop (insn
, operand
, mods
, value
, errmsg
)
2125 const struct txvu_operand
*operand
;
2128 const char **errmsg
;
2133 extract_gpuif_nloop (insn
, operand
, mods
, pinvalid
)
2135 const struct txvu_operand
*operand
;
2143 print_gpuif_nloop (info
, insn
, value
)
2144 disassemble_info
*info
;
2148 (*info
->fprintf_func
) (info
->stream
, "???");
2152 parse_gpuif_eop (pstr
, errmsg
)
2154 const char **errmsg
;
2156 if (strncasecmp (*pstr
, "eop", 3) == 0)
2161 *errmsg
= "missing `EOP'";
2166 insert_gpuif_eop (insn
, operand
, mods
, value
, errmsg
)
2168 const struct txvu_operand
*operand
;
2171 const char **errmsg
;
2176 extract_gpuif_eop (insn
, operand
, mods
, pinvalid
)
2178 const struct txvu_operand
*operand
;
2186 print_gpuif_eop (info
, insn
, value
)
2187 disassemble_info
*info
;
2191 (*info
->fprintf_func
) (info
->stream
, "???");
2195 These are called before doing each of the respective activities. */
2197 /* Called by the assembler before parsing an instruction. */
2200 txvu_opcode_init_parse ()
2206 /* Called by the disassembler before printing an instruction. */
2209 txvu_opcode_init_print ()
2215 /* Indexed by first letter of opcode. Points to chain of opcodes with same
2217 /* ??? One can certainly use a better hash. Later. */
2218 static struct txvu_opcode
*upper_opcode_map
[26 + 1];
2219 static struct txvu_opcode
*lower_opcode_map
[26 + 1];
2221 /* Indexed by insn code. Points to chain of opcodes with same insn code. */
2222 static struct txvu_opcode
*upper_icode_map
[(1 << TXVU_ICODE_HASH_SIZE
) - 1];
2223 static struct txvu_opcode
*lower_icode_map
[(1 << TXVU_ICODE_HASH_SIZE
) - 1];
2225 /* Initialize any tables that need it.
2226 Must be called once at start up (or when first needed).
2228 FLAGS is currently unused but is intended to control initialization. */
2231 txvu_opcode_init_tables (flags
)
2234 static int init_p
= 0;
2236 /* We may be intentionally called more than once (for example gdb will call
2237 us each time the user switches cpu). These tables only need to be init'd
2239 /* ??? We can remove the need for txvu_opcode_supported by taking it into
2240 account here, but I'm not sure I want to do that yet (if ever). */
2245 /* Upper VU table. */
2247 memset (upper_opcode_map
, 0, sizeof (upper_opcode_map
));
2248 memset (upper_icode_map
, 0, sizeof (upper_icode_map
));
2249 /* Scan the table backwards so macros appear at the front. */
2250 for (i
= txvu_upper_opcodes_count
- 1; i
>= 0; --i
)
2252 int opcode_hash
= TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes
[i
].mnemonic
);
2253 int icode_hash
= TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes
[i
].value
);
2255 txvu_upper_opcodes
[i
].next_asm
= upper_opcode_map
[opcode_hash
];
2256 upper_opcode_map
[opcode_hash
] = &txvu_upper_opcodes
[i
];
2258 txvu_upper_opcodes
[i
].next_dis
= upper_icode_map
[icode_hash
];
2259 upper_icode_map
[icode_hash
] = &txvu_upper_opcodes
[i
];
2262 /* Lower VU table. */
2264 memset (lower_opcode_map
, 0, sizeof (lower_opcode_map
));
2265 memset (lower_icode_map
, 0, sizeof (lower_icode_map
));
2266 /* Scan the table backwards so macros appear at the front. */
2267 for (i
= txvu_lower_opcodes_count
- 1; i
>= 0; --i
)
2269 int opcode_hash
= TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes
[i
].mnemonic
);
2270 int icode_hash
= TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes
[i
].value
);
2272 txvu_lower_opcodes
[i
].next_asm
= lower_opcode_map
[opcode_hash
];
2273 lower_opcode_map
[opcode_hash
] = &txvu_lower_opcodes
[i
];
2275 txvu_lower_opcodes
[i
].next_dis
= lower_icode_map
[icode_hash
];
2276 lower_icode_map
[icode_hash
] = &txvu_lower_opcodes
[i
];
2279 /* FIXME: We just hash everything to the same value for the rest.
2280 Quick hack while other things are worked on. */
2284 for (i
= pke_opcodes_count
- 2; i
>= 0; --i
)
2286 pke_opcodes
[i
].next_asm
= & pke_opcodes
[i
+1];
2287 pke_opcodes
[i
].next_dis
= & pke_opcodes
[i
+1];
2292 for (i
= dma_opcodes_count
- 2; i
>= 0; --i
)
2294 dma_opcodes
[i
].next_asm
= & dma_opcodes
[i
+1];
2295 dma_opcodes
[i
].next_dis
= & dma_opcodes
[i
+1];
2300 for (i
= gpuif_opcodes_count
- 2; i
>= 0; --i
)
2302 gpuif_opcodes
[i
].next_asm
= & gpuif_opcodes
[i
+1];
2303 gpuif_opcodes
[i
].next_dis
= & gpuif_opcodes
[i
+1];
2310 /* Return the first insn in the chain for assembling upper INSN. */
2312 const struct txvu_opcode
*
2313 txvu_upper_opcode_lookup_asm (insn
)
2316 return upper_opcode_map
[TXVU_HASH_UPPER_OPCODE (insn
)];
2319 /* Return the first insn in the chain for disassembling upper INSN. */
2321 const struct txvu_opcode
*
2322 txvu_upper_opcode_lookup_dis (insn
)
2325 return upper_icode_map
[TXVU_HASH_UPPER_ICODE (insn
)];
2328 /* Return the first insn in the chain for assembling lower INSN. */
2330 const struct txvu_opcode
*
2331 txvu_lower_opcode_lookup_asm (insn
)
2334 return lower_opcode_map
[TXVU_HASH_LOWER_OPCODE (insn
)];
2337 /* Return the first insn in the chain for disassembling lower INSN. */
2339 const struct txvu_opcode
*
2340 txvu_lower_opcode_lookup_dis (insn
)
2343 return lower_icode_map
[TXVU_HASH_LOWER_ICODE (insn
)];
2346 /* Return the first insn in the chain for assembling lower INSN. */
2348 const struct txvu_opcode
*
2349 pke_opcode_lookup_asm (insn
)
2352 return &pke_opcodes
[0];
2355 /* Return the first insn in the chain for disassembling lower INSN. */
2357 const struct txvu_opcode
*
2358 pke_opcode_lookup_dis (insn
)
2361 return &pke_opcodes
[0];
2364 /* Return the first insn in the chain for assembling lower INSN. */
2366 const struct txvu_opcode
*
2367 dma_opcode_lookup_asm (insn
)
2370 return &dma_opcodes
[0];
2373 /* Return the first insn in the chain for disassembling lower INSN. */
2375 const struct txvu_opcode
*
2376 dma_opcode_lookup_dis (insn
)
2379 return &dma_opcodes
[0];
2382 /* Return the first insn in the chain for assembling lower INSN. */
2384 const struct txvu_opcode
*
2385 gpuif_opcode_lookup_asm (insn
)
2388 return &gpuif_opcodes
[0];
2391 /* Return the first insn in the chain for disassembling lower INSN. */
2393 const struct txvu_opcode
*
2394 gpuif_opcode_lookup_dis (insn
)
2397 return &gpuif_opcodes
[0];
2400 /* Misc. utilities. */
2402 /* Scan a symbol and return a pointer to one past the end. */
2408 while (*sym
&& issymchar (*sym
))
2413 /* Given a keyword, look up its value, or -1 if not found. */
2416 lookup_keyword_value (table
, name
, case_sensitive_p
)
2417 const keyword
*table
;
2419 int case_sensitive_p
;
2423 if (case_sensitive_p
)
2425 for (p
= table
; p
->name
; ++p
)
2426 if (strcmp (name
, p
->name
) == 0)
2431 for (p
= table
; p
->name
; ++p
)
2432 if (strcasecmp (name
, p
->name
) == 0)
2439 /* Given a keyword's value, look up its name, or NULL if not found. */
2442 lookup_keyword_name (table
, value
)
2443 const keyword
*table
;
2448 for (p
= table
; p
->name
; ++p
)
2449 if (value
== p
->value
)