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 ((const txvu_opcode *, const txvu_operand *, int, char **, \
58 #define INSERT_FN(fn) \
59 static void CONCAT2 (insert_,fn) \
60 PARAMS ((const txvu_opcode *, const txvu_operand *, int, TXVU_INSN *, \
62 #define EXTRACT_FN(fn) \
63 static long CONCAT2 (extract_,fn) \
64 PARAMS ((const txvu_opcode *, const txvu_operand *, int, TXVU_INSN *, \
66 #define PRINT_FN(fn) \
67 static void CONCAT2 (print_,fn) \
68 PARAMS ((const txvu_opcode *, const txvu_operand *, int, TXVU_INSN *, \
69 disassemble_info *, long));
103 EXTRACT_FN (ffstreg);
110 EXTRACT_FN (luimm12);
112 INSERT_FN (luimm12up6);
115 EXTRACT_FN (luimm15);
117 /* Various types of TXVU operands, including insn suffixes.
121 BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
123 Operand values are 128 + table index. This allows ASCII chars to be
124 included in the syntax spec. */
126 const txvu_operand txvu_operands[] =
128 /* place holder (??? not sure if needed) */
132 /* Operands that exist in the same place for essentially the same purpose
133 in both upper and lower instructions. These don't have a U or L prefix.
134 Operands specific to the upper or lower instruction are so prefixed. */
136 /* Destination indicator attached to mnemonic, with leading '.' or '/'.
137 After parsing this, the value is stored in global `dest' so that the
138 register parser can verify the same choice of xyzw is used. */
139 #define DOTDEST (UNUSED + 1)
140 { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
141 parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest },
143 /* ft reg, with vector specification same as DOTDEST */
144 #define VFTREG (DOTDEST + 1)
145 { 5, TXVU_SHIFT_TREG, 0, parse_vfreg, 0, 0, print_vfreg },
147 /* fs reg, with vector specification same as DOTDEST */
148 #define VFSREG (VFTREG + 1)
149 { 5, TXVU_SHIFT_SREG, 0, parse_vfreg, 0, 0, print_vfreg },
151 /* fd reg, with vector specification same as DOTDEST */
152 #define VFDREG (VFSREG + 1)
153 { 5, TXVU_SHIFT_DREG, 0, parse_vfreg, 0, 0, print_vfreg },
155 /* Upper word operands. */
158 #define UBC (VFDREG + 1)
159 { 2, 0, TXVU_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest },
161 /* ftreg in broadcast case */
162 #define UBCFTREG (UBC + 1)
163 { 5, TXVU_SHIFT_TREG, 0, parse_bcftreg, 0, 0, print_bcftreg },
165 /* accumulator dest */
166 #define UACCDEST (UBCFTREG + 1)
167 { 0, 0, 0, parse_accdest, 0, 0, print_accdest },
169 /* The XYZ operand is a fake one that is used to ensure only "xyz" is
170 specified. It simplifies the opmula and opmsub entries. */
171 #define UXYZ (UACCDEST + 1)
172 { 0, 0, TXVU_OPERAND_FAKE, 0, insert_xyz, 0, 0 },
174 /* Lower word operands. */
176 /* 5 bit signed immediate. */
177 #define LIMM5 (UXYZ + 1)
178 { 5, 6, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
180 /* 11 bit signed immediate. */
181 #define LIMM11 (LIMM5 + 1)
182 { 11, 0, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
184 /* 15 bit unsigned immediate. */
185 #define LUIMM15 (LIMM11 + 1)
186 { 15, 0, 0, 0, insert_luimm15, extract_luimm15, 0 },
189 #define LIDREG (LUIMM15 + 1)
190 { 5, 6, 0, parse_ireg, 0, 0, print_ireg },
193 #define LISREG (LIDREG + 1)
194 { 5, 11, 0, parse_ireg, 0, 0, print_ireg },
197 #define LITREG (LISREG + 1)
198 { 5, 16, 0, parse_ireg, 0, 0, print_ireg },
200 /* FS reg, with FSF field selector. */
201 #define LFSFFSREG (LITREG + 1)
202 { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
204 /* FS reg, no selector (choice of x,y,z,w is provided by opcode). */
205 #define LFSREG (LFSFFSREG + 1)
206 { 5, 11, 0, parse_freg, 0, 0, print_freg },
208 /* FT reg, with FTF field selector. */
209 #define LFTFFTREG (LFSREG + 1)
210 { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
213 #define LVI01 (LFTFFTREG + 1)
214 { 0, 0, 0, parse_vi01, 0, 0, print_vi01 },
216 /* 24 bit unsigned immediate. */
217 #define LUIMM24 (LVI01 + 1)
218 { 24, 0, 0, 0, 0, 0, 0 },
220 /* 12 bit unsigned immediate, split into 1 and 11 bit pieces. */
221 #define LUIMM12 (LUIMM24 + 1)
222 { 12, 0, 0, 0, insert_luimm12, extract_luimm12, 0 },
224 /* upper 6 bits of 12 bit unsigned immediate */
225 #define LUIMM12UP6 (LUIMM12 + 1)
226 { 12, 0, 0, 0, insert_luimm12up6, extract_luimm12, 0 },
228 /* 11 bit pc-relative signed immediate. */
229 #define LPCREL11 (LUIMM12UP6 + 1)
230 { 11, 0, TXVU_OPERAND_SIGNED + TXVU_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 },
232 /* Destination indicator, single letter only, with leading '.' or '/'. */
233 #define LDOTDEST1 (LPCREL11 + 1)
234 { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
235 /* Note that we borrow the insert/extract/print functions from the
237 parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
239 /* Destination indicator, single letter only, no leading '.'. */
240 #define LDEST1 (LDOTDEST1 + 1)
241 { 0, 0, 0, parse_dest1, 0, 0, print_dest1 },
243 /* end of list place holder */
247 /* Macros to put a field's value into the right place. */
248 /* ??? If assembler needs these, move to opcode/txvu.h. */
250 /* value X, B bits, shift S */
251 #define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s))
253 /* Field value macros for both upper and lower instructions.
254 These shift a value into the right place in the instruction. */
256 /* [FI] T reg field (remember it's V for value, not vector, here). */
257 #define VT(x) V ((x), 5, TXVU_SHIFT_TREG)
258 /* [FI] S reg field. */
259 #define VS(x) V ((x), 5, TXVU_SHIFT_SREG)
260 /* [FI] D reg field. */
261 #define VD(x) V ((x), 5, TXVU_SHIFT_DREG)
263 #define VDEST(x) V ((x), 4, 21)
265 /* Masks for fields in both upper and lower instructions.
266 These mask out all bits but the ones for the field in the instruction. */
271 #define MDEST VDEST (~0)
273 /* Upper instruction Value macros. */
275 /* Upper Flag bits. */
276 #define VUF(x) V ((x), 5, 27)
277 /* Upper REServed two bits next to flag bits. */
278 #define VURES(x) V ((x), 2, 25)
279 /* 4 bit opcode field. */
280 #define VUOP4(x) V ((x), 4, 2)
281 /* 6 bit opcode field. */
282 #define VUOP6(x) V ((x), 6, 0)
283 /* 9 bit opcode field. */
284 #define VUOP9(x) V ((x), 9, 2)
285 /* 11 bit opcode field. */
286 #define VUOP11(x) V ((x), 11, 0)
287 /* BroadCast field. */
288 #define VUBC(x) V ((x), 2, 0)
290 /* Upper instruction field masks. */
291 #define MUUBITS (VUF (~0) + VURES (~0))
292 #define MURES VURES (~0)
293 #define MUOP4 VUOP4 (~0)
294 #define MUOP6 VUOP6 (~0)
295 #define MUOP9 VUOP9 (~0)
296 #define MUOP11 VUOP11 (~0)
298 /* A space, separates instruction name (mnemonic + mnemonic operands) from
301 /* Commas separate operands. */
303 /* Special I,P,Q,R operands. */
309 /* TXVU instructions.
310 [??? some of these comments are left over from the ARC port from which
311 this code is borrowed, delete in time]
313 Longer versions of insns must appear before shorter ones (if gas sees
314 "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
315 junk). This isn't necessary for `ld' because of the trailing ']'.
317 Instructions that are really macros based on other insns must appear
318 before the real insn so they're chosen when disassembling. Eg: The `mov'
319 insn is really the `and' insn.
321 This table is best viewed on a wide screen (161 columns). I'd prefer to
322 keep it this way. The rest of the file, however, should be viewable on an
323 80 column terminal. */
325 /* ??? This table also includes macros: asl, lsl, and mov. The ppc port has
326 a more general facility for dealing with macros which could be used if
329 /* These tables can't be `const' because members `next_asm' and `next_dis' are
330 computed at run-time. We could split this into two, as that would put the
331 constant stuff into a readonly section. */
333 struct txvu_opcode txvu_upper_opcodes[] =
335 /* Macros appear first, so the disassembler will try them first. */
336 /* ??? Any aliases? */
337 /* ??? When close to being finished, clean up by aligning fields. */
339 /* The rest of these needn't be sorted, but it helps to find them if they are. */
340 { "abs", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x1fd) },
341 { "add", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x28) },
342 { "addi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x22) },
343 { "addq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x20) },
344 { "add", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (0) },
345 { "adda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bc) },
346 { "addai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23e) },
347 { "addaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23c) },
348 { "adda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0xf) },
349 { "clip", { DOTDEST, SP, VFSREG }, MURES + MDEST + MT + MUOP11, VDEST (0xf) + VUOP11 (0x1ff) },
350 { "ftoi0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17c) },
351 { "ftoi4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17d) },
352 { "ftoi12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17e) },
353 { "ftoi15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17f) },
354 { "itof0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13c) },
355 { "itof4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13d) },
356 { "itof12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13e) },
357 { "itof15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13f) },
358 { "madd", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x29) },
359 { "maddi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x23) },
360 { "maddq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x21) },
361 { "madd", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x2) },
362 { "madda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bd) },
363 { "maddai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23f) },
364 { "maddaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23d) },
365 { "madda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x2f) },
366 { "max", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2b) },
367 { "maxi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x2d) },
368 { "max", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x4) },
369 /* ??? mini or min? */
370 { "mini", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2f) },
371 { "minii", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1f) },
372 { "mini", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x5) },
373 { "msub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2d) },
374 { "msubi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x27) },
375 { "msubq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x25) },
376 { "msub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x3) },
377 { "msuba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fd) },
378 { "msubai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27f) },
379 { "msubaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27d) },
380 { "msuba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x3f) },
381 { "mul", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2a) },
382 { "muli", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1e) },
383 { "mulq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x1c) },
384 { "mul", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (6) },
385 { "mula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2be) },
386 { "mulai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x1fe) },
387 { "mulaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x1fc) },
388 { "mula", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x6f) },
389 { "nop", { 0 }, MURES + MDEST + MT + MS + MUOP11, VUOP11 (0x2ff) },
390 { "opmula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP11, VUOP11 (0x2fe) },
391 { "opmsub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP6, VUOP6 (0x2e) },
392 { "sub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2c) },
393 { "subi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x26) },
394 { "subq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x24) },
395 { "sub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (1) },
396 { "suba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fc) },
397 { "subai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27e) },
398 { "subaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27c) },
399 { "suba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x1f) }
401 const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_upper_opcodes[0]);
403 /* Lower instruction Value macros. */
406 #define VLOP6(x) V ((x), 6, 0)
408 #define VLOP7(x) V ((x), 7, 25)
410 #define VLOP11(x) V ((x), 11, 0)
411 /* 11 bit immediate. */
412 #define VLIMM11(x) V ((x), 11, 0)
414 #define VLFTF(x) V ((x), 2, 23)
416 #define VLFSF(x) V ((x), 2, 21)
417 /* Upper bit of 12 bit unsigned immediate. */
418 #define VLUIMM12TOP(x) V ((x), 1, 21)
419 /* Upper 4 bits of 15 bit unsigned immediate. */
420 #define VLUIMM15TOP(x) VDEST (x)
422 /* Lower instruction field masks. */
423 #define MLOP6 VLOP6 (~0)
424 #define MLOP7 VLOP7 (~0)
425 #define MLOP11 VLOP11 (~0)
426 #define MLIMM11 VLIMM11 (~0)
427 #define MLB24 V (1, 1, 24)
428 #define MLUIMM12TOP VLUIMM12TOP (~0)
429 /* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits.
430 The upper 1 bit is part of the `dest' field. This mask is for the
431 other 3 bits of the dest field. */
432 #define MLUIMM12UNUSED V (7, 3, 22)
433 #define MLUIMM15TOP MDEST
435 struct txvu_opcode txvu_lower_opcodes[] =
437 /* Macros appear first, so the disassembler will try them first. */
438 /* ??? Any aliases? */
439 /* ??? There isn't an explicit nop. Apparently it's "move vf0,vf0". */
440 { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) },
442 /* The rest of these needn't be sorted, but it helps to find them if they are. */
443 { "b", { SP, LPCREL11 }, MLOP7 + MDEST + MT + MS, VLOP7 (0x20) },
444 { "bal", { SP, LITREG, C, LPCREL11 }, MLOP7 + MDEST + MS, VLOP7 (0x21) },
445 { "div", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLOP11, VLOP7 (0x40) + VLOP11 (0x3bc) },
446 { "eatan", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) },
447 { "eatanxy", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77c) },
448 { "eatanxz", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77d) },
449 { "eexp", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) },
450 { "eleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x74e) },
451 { "ercpr", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) },
452 { "erleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73f) },
453 { "ersadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73d) },
454 { "ersqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) },
455 { "esadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73c) },
456 { "esin", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) },
457 { "esqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) },
458 { "esum", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) },
459 { "fcand", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x12) },
460 { "fceq", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) },
461 { "fcget", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x1c) },
462 { "fcor", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) },
463 { "fcset", { SP, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) },
464 { "fmand", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1a) },
465 { "fmeq", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x18) },
466 { "fmor", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1b) },
467 { "fsand", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x16) },
468 { "fseq", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x14) },
469 { "fsor", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x17) },
470 { "fsset", { SP, LUIMM12UP6 }, MLOP7 + MLUIMM12UNUSED + V (~0, 6, 0) + MS + MT, VLOP7 (0x15) },
471 { "iadd", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x30) },
472 { "iaddi", { SP, LITREG, C, LISREG, C, LIMM5 }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x32) },
473 { "iaddiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x08) },
474 { "iand", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
475 { "ibeq", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x28) },
476 { "ibgez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2f) },
477 { "ibgtz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2d) },
478 { "iblez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2e) },
479 { "ibltz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2c) },
480 { "ibne", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x29) },
481 { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x04) },
482 { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fe) },
483 { "ior", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x35) },
484 { "isub", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x31) },
485 { "isubiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x09) },
486 { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x05) },
487 { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3ff) },
488 { "jalr", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x25) },
489 { "jr", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x24) },
490 { "lq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x00) },
491 { "lqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37e) },
492 { "lqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37c) },
493 /* Only a single VF reg is allowed here. We can use VFTREG because LDOTDEST1
494 handles verifying only a single choice of xyzw is present. */
495 { "mfir", { LDOTDEST1, SP, VFTREG, C, LISREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fc) },
496 { "mfp", { DOTDEST, SP, VFTREG, C, P }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x67c) },
497 { "move", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33c) },
498 { "mr32", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33d) },
499 { "mtir", { LDOTDEST1, SP, LITREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) },
500 { "rget", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43d) },
501 { "rinit", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) },
502 { "rnext", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43c) },
503 { "rsqrt", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3be) },
504 { "rxor", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
505 { "sq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x01) },
506 { "sqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37f) },
507 { "sqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37d) },
508 { "sqrt", { SP, Q, C, LFTFFTREG }, MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) },
509 { "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) },
510 { "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) },
511 { "xgkick", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) },
512 { "xitop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) },
513 { "xtop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) }
515 const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]);
517 /* Value of DEST in use.
518 Each of the registers must specify the same value as the opcode.
519 ??? Perhaps remove the duplication? */
520 static int state_vu_mnemonic_dest;
522 /* Value of BC to use.
523 The register specified for the ftreg must match the broadcast register
524 specified in the opcode. */
525 static int state_vu_mnemonic_bc;
527 /* Multiple destination choice support.
528 The "dest" string selects any combination of x,y,z,w.
529 [The letters are ordered that way to follow the manual's style.] */
531 /* Utility to parse a `dest' spec.
532 Return the found value.
533 *PSTR is set to the character that terminated the parsing.
534 It is up to the caller to do any error checking. */
546 case 'x' : case 'X' : dest |= TXVU_DEST_X; break;
547 case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break;
548 case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break;
549 case 'w' : case 'W' : dest |= TXVU_DEST_W; break;
550 default : return dest;
559 parse_dotdest (opcode, operand, mods, pstr, errmsg)
560 const txvu_opcode *opcode;
561 const txvu_operand *operand;
568 if (**pstr != '.' && **pstr != '/')
570 *errmsg = "missing `.'";
575 dest = u_parse_dest (pstr);
576 if (dest == 0 || isalnum (**pstr))
578 *errmsg = "invalid `dest'";
585 /* Parse a `dest' spec where only a single letter is allowed,
586 but the encoding handles all four. */
589 parse_dotdest1 (opcode, operand, mods, pstr, errmsg)
590 const txvu_opcode *opcode;
591 const txvu_operand *operand;
599 if (**pstr != '.' && **pstr != '/')
601 *errmsg = "missing `.'";
608 case 'x' : case 'X' : dest = TXVU_DEST_X; break;
609 case 'y' : case 'Y' : dest = TXVU_DEST_Y; break;
610 case 'z' : case 'Z' : dest = TXVU_DEST_Z; break;
611 case 'w' : case 'W' : dest = TXVU_DEST_W; break;
612 default : *errmsg = "invalid `dest'"; return 0;
615 c = tolower (**pstr);
616 if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
618 *errmsg = "only one of x,y,z,w can be specified";
621 if (isalnum (**pstr))
623 *errmsg = "invalid `dest'";
630 /* Parse a `dest' spec with no leading '.', where only a single letter is
631 allowed, but the encoding handles all four. The parsed value must match
632 that recorded in `dest'. */
635 parse_dest1 (opcode, operand, mods, pstr, errmsg)
636 const txvu_opcode *opcode;
637 const txvu_operand *operand;
645 dest = u_parse_dest (pstr);
646 if (dest != TXVU_DEST_X
647 && dest != TXVU_DEST_Y
648 && dest != TXVU_DEST_Z
649 && dest != TXVU_DEST_W)
651 *errmsg = "expecting one of x,y,z,w";
655 if (dest != state_vu_mnemonic_dest)
657 *errmsg = "`dest' suffix does not match instruction `dest'";
665 insert_dotdest (opcode, operand, mods, insn, value, errmsg)
666 const txvu_opcode *opcode;
667 const txvu_operand *operand;
673 /* Record the DEST value in use so the register parser can use it. */
674 state_vu_mnemonic_dest = value;
675 *insn |= value << operand->shift;
679 extract_dotdest (opcode, operand, mods, insn, pinvalid)
680 const txvu_opcode *opcode;
681 const txvu_operand *operand;
686 /* Record the DEST value in use so the register printer can use it. */
687 state_vu_mnemonic_dest = (*insn >> operand->shift) & ((1 << operand->bits) - 1);
688 return state_vu_mnemonic_dest;
691 /* Utility to print a multiple dest spec. */
694 u_print_dest (info, insn, value)
695 disassemble_info *info;
699 if (value & TXVU_DEST_X)
700 (*info->fprintf_func) (info->stream, "x");
701 if (value & TXVU_DEST_Y)
702 (*info->fprintf_func) (info->stream, "y");
703 if (value & TXVU_DEST_Z)
704 (*info->fprintf_func) (info->stream, "z");
705 if (value & TXVU_DEST_W)
706 (*info->fprintf_func) (info->stream, "w");
710 print_dotdest (opcode, operand, mods, insn, info, value)
711 const txvu_opcode *opcode;
712 const txvu_operand *operand;
715 disassemble_info *info;
718 (*info->fprintf_func) (info->stream, ".");
719 u_print_dest (info, insn, value);
723 print_dest1 (opcode, operand, mods, insn, info, value)
724 const txvu_opcode *opcode;
725 const txvu_operand *operand;
728 disassemble_info *info;
731 u_print_dest (info, insn, state_vu_mnemonic_dest);
734 /* Utilities for single destination choice handling. */
737 u_parse_sdest (pstr, errmsg)
746 case 'x' : case 'X' : dest = TXVU_SDEST_X; break;
747 case 'y' : case 'Y' : dest = TXVU_SDEST_Y; break;
748 case 'z' : case 'Z' : dest = TXVU_SDEST_Z; break;
749 case 'w' : case 'W' : dest = TXVU_SDEST_W; break;
750 default : *errmsg = "only one of x,y,z,w can be specified"; return 0;
753 c = tolower (**pstr);
754 if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
756 *errmsg = "only one of x,y,z,w can be specified";
759 if (isalnum (**pstr))
761 *errmsg = "invalid `dest'";
769 print_sdest (opcode, operand, mods, insn, info, value)
770 const txvu_opcode *opcode;
771 const txvu_operand *operand;
774 disassemble_info *info;
781 case TXVU_SDEST_X : c = 'x'; break;
782 case TXVU_SDEST_Y : c = 'y'; break;
783 case TXVU_SDEST_Z : c = 'z'; break;
784 case TXVU_SDEST_W : c = 'w'; break;
787 (*info->fprintf_func) (info->stream, "%c", c);
790 /* Broadcase field. */
793 parse_bc (opcode, operand, mods, pstr, errmsg)
794 const txvu_opcode *opcode;
795 const txvu_operand *operand;
800 long value = u_parse_sdest (pstr, errmsg);
804 /* Save value for later verification in register parsing. */
805 state_vu_mnemonic_bc = value;
809 /* During the extraction process, save the bc field for use in
810 printing the bc register. */
813 extract_bc (opcode, operand, mods, insn, pinvalid)
814 const txvu_opcode *opcode;
815 const txvu_operand *operand;
820 state_vu_mnemonic_bc = *insn & 3;
821 return state_vu_mnemonic_bc;
825 parse_vfreg (opcode, operand, mods, pstr, errmsg)
826 const txvu_opcode *opcode;
827 const txvu_operand *operand;
837 if (tolower (str[0]) != 'v'
838 || tolower (str[1]) != 'f')
840 *errmsg = "unknown register";
844 /* FIXME: quick hack until the framework works. */
845 start = str = str + 2;
846 while (*str && isdigit (*str))
849 if (reg < 0 || reg > 31)
851 *errmsg = "invalid register number";
854 reg_dest = u_parse_dest (&str);
855 if (reg_dest == 0 || isalnum (*str))
857 *errmsg = "invalid `dest'";
860 if (reg_dest != state_vu_mnemonic_dest)
862 *errmsg = "register `dest' does not match instruction `dest'";
870 print_vfreg (opcode, operand, mods, insn, info, value)
871 const txvu_opcode *opcode;
872 const txvu_operand *operand;
874 disassemble_info *info;
878 (*info->fprintf_func) (info->stream, "vf%02ld", value);
879 u_print_dest (info, insn, state_vu_mnemonic_dest);
882 /* FT register in broadcast case. */
885 parse_bcftreg (opcode, operand, mods, pstr, errmsg)
886 const txvu_opcode *opcode;
887 const txvu_operand *operand;
897 if (tolower (str[0]) != 'v'
898 || tolower (str[1]) != 'f')
900 *errmsg = "unknown register";
904 /* FIXME: quick hack until the framework works. */
905 start = str = str + 2;
906 while (*str && isdigit (*str))
909 if (reg < 0 || reg > 31)
911 *errmsg = "invalid register number";
914 reg_bc = u_parse_sdest (&str, errmsg);
917 if (reg_bc != state_vu_mnemonic_bc)
919 *errmsg = "register `bc' does not match instruction `bc'";
927 print_bcftreg (opcode, operand, mods, insn, info, value)
928 const txvu_opcode *opcode;
929 const txvu_operand *operand;
932 disassemble_info *info;
935 (*info->fprintf_func) (info->stream, "vf%02ld", value);
936 print_sdest (opcode, operand, mods, insn, info, state_vu_mnemonic_bc);
942 parse_accdest (opcode, operand, mods, pstr, errmsg)
943 const txvu_opcode *opcode;
944 const txvu_operand *operand;
952 if (strncasecmp (str, "acc", 3) != 0)
954 *errmsg = "expecting `acc'";
958 acc_dest = u_parse_dest (&str);
959 if (acc_dest == 0 || isalnum (*str))
961 *errmsg = "invalid `dest'";
964 if (acc_dest != state_vu_mnemonic_dest)
966 *errmsg = "acc `dest' does not match instruction `dest'";
970 /* Value isn't used, but we must return something. */
975 print_accdest (opcode, operand, mods, insn, info, value)
976 const txvu_opcode *opcode;
977 const txvu_operand *operand;
979 disassemble_info *info;
983 (*info->fprintf_func) (info->stream, "acc");
984 u_print_dest (info, insn, state_vu_mnemonic_dest);
987 /* XYZ operand handling.
988 This simplifies the opmula,opmsub entries by keeping them equivalent to
992 insert_xyz (opcode, operand, mods, insn, value, errmsg)
993 const txvu_opcode *opcode;
994 const txvu_operand *operand;
1000 if (state_vu_mnemonic_dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
1001 *errmsg = "expecting `xyz' for `dest' value";
1004 /* F[ST] register using selector in F[ST]F field.
1005 Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator
1006 followed by the 5 bit register number. */
1009 parse_ffstreg (opcode, operand, mods, pstr, errmsg)
1010 const txvu_opcode *opcode;
1011 const txvu_operand *operand;
1014 const char **errmsg;
1020 if (tolower (str[0]) != 'v'
1021 || tolower (str[1]) != 'f')
1023 *errmsg = "unknown register";
1027 /* FIXME: quick hack until the framework works. */
1028 start = str = str + 2;
1029 while (*str && isdigit (*str))
1032 if (reg < 0 || reg > 31)
1034 *errmsg = "invalid register number";
1037 xyzw = u_parse_sdest (&str, errmsg);
1041 return reg | (xyzw << 5);
1045 print_ffstreg (opcode, operand, mods, insn, info, value)
1046 const txvu_opcode *opcode;
1047 const txvu_operand *operand;
1050 disassemble_info *info;
1053 (*info->fprintf_func) (info->stream, "vf%02ld", value & TXVU_MASK_REG);
1054 print_sdest (opcode, operand, mods, insn, info, (value >> 5) & 3);
1058 insert_ffstreg (opcode, operand, mods, insn, value, errmsg)
1059 const txvu_opcode *opcode;
1060 const txvu_operand *operand;
1064 const char **errmsg;
1066 if (operand->shift == TXVU_SHIFT_SREG)
1067 *insn |= VLFSF (value >> 5) | VS (value);
1069 *insn |= VLFTF (value >> 5) | VT (value);
1073 extract_ffstreg (opcode, operand, mods, insn, pinvalid)
1074 const txvu_opcode *opcode;
1075 const txvu_operand *operand;
1080 if (operand->shift == TXVU_SHIFT_SREG)
1081 return (((*insn & VLFSF (~0)) >> 21) << 5) | VS (*insn);
1083 return (((*insn & VLFTF (~0)) >> 21) << 5) | VT (*insn);
1089 parse_freg (opcode, operand, mods, pstr, errmsg)
1090 const txvu_opcode *opcode;
1091 const txvu_operand *operand;
1094 const char **errmsg;
1100 if (tolower (str[0]) != 'v'
1101 || tolower (str[1]) != 'f')
1103 *errmsg = "unknown register";
1107 /* FIXME: quick hack until the framework works. */
1108 start = str = str + 2;
1109 while (*str && isdigit (*str))
1112 if (reg < 0 || reg > 31)
1114 *errmsg = "invalid register number";
1122 print_freg (opcode, operand, mods, insn, info, value)
1123 const txvu_opcode *opcode;
1124 const txvu_operand *operand;
1127 disassemble_info *info;
1130 (*info->fprintf_func) (info->stream, "vf%02ld", value);
1136 parse_ireg (opcode, operand, mods, pstr, errmsg)
1137 const txvu_opcode *opcode;
1138 const txvu_operand *operand;
1141 const char **errmsg;
1147 if (tolower (str[0]) != 'v'
1148 || tolower (str[1]) != 'i')
1150 *errmsg = "unknown register";
1154 /* FIXME: quick hack until the framework works. */
1155 start = str = str + 2;
1156 while (*str && isdigit (*str))
1159 if (reg < 0 || reg > 31)
1161 *errmsg = "invalid register number";
1169 print_ireg (opcode, operand, mods, insn, info, value)
1170 const txvu_opcode *opcode;
1171 const txvu_operand *operand;
1174 disassemble_info *info;
1177 (*info->fprintf_func) (info->stream, "vi%02ld", value);
1180 /* VI01 register. */
1183 parse_vi01 (opcode, operand, mods, pstr, errmsg)
1184 const txvu_opcode *opcode;
1185 const txvu_operand *operand;
1188 const char **errmsg;
1194 if (tolower (str[0]) != 'v'
1195 || tolower (str[1]) != 'i')
1197 *errmsg = "unknown register";
1201 /* FIXME: quick hack until the framework works. */
1202 start = str = str + 2;
1203 while (*str && isdigit (*str))
1208 *errmsg = "vi01 required here";
1216 print_vi01 (opcode, operand, mods, insn, info, value)
1217 const txvu_opcode *opcode;
1218 const txvu_operand *operand;
1221 disassemble_info *info;
1224 (*info->fprintf_func) (info->stream, "vi01");
1227 /* Lower instruction 12 bit unsigned immediate. */
1230 insert_luimm12 (opcode, operand, mods, insn, value, errmsg)
1231 const txvu_opcode *opcode;
1232 const txvu_operand *operand;
1236 const char **errmsg;
1238 *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | VLIMM11 (value);
1242 extract_luimm12 (opcode, operand, mods, insn, pinvalid)
1243 const txvu_opcode *opcode;
1244 const txvu_operand *operand;
1249 return (((*insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (*insn);
1252 /* Lower instruction 12 bit unsigned immediate, upper 6 bits. */
1255 insert_luimm12up6 (opcode, operand, mods, insn, value, errmsg)
1256 const txvu_opcode *opcode;
1257 const txvu_operand *operand;
1261 const char **errmsg;
1263 *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | (value & 0x7c0);
1266 /* Lower instruction 15 bit unsigned immediate. */
1269 insert_luimm15 (opcode, operand, mods, insn, value, errmsg)
1270 const txvu_opcode *opcode;
1271 const txvu_operand *operand;
1275 const char **errmsg;
1277 *insn |= VLUIMM15TOP (value >> 11) | VLIMM11 (value);
1281 extract_luimm15 (opcode, operand, mods, insn, pinvalid)
1282 const txvu_opcode *opcode;
1283 const txvu_operand *operand;
1288 return (((*insn & MLUIMM15TOP) >> 21) << 11) | VLIMM11 (*insn);
1293 PARSE_FN (pke_ibit);
1294 PRINT_FN (pke_ibit);
1296 PARSE_FN (pke_mode);
1297 PRINT_FN (pke_mode);
1299 PARSE_FN (pke_ability);
1300 PRINT_FN (pke_ability);
1302 PARSE_FN (pke_mpgaddr);
1304 PARSE_FN (pke_varlendata);
1306 PARSE_FN (pke_imrbits);
1307 PRINT_FN (pke_imrbits);
1309 PARSE_FN (pke_unpacktype);
1310 PRINT_FN (pke_unpacktype);
1312 PARSE_FN (pke_unpackaddr);
1314 const txvu_operand pke_operands[] =
1316 /* place holder (??? not sure if needed) */
1317 #define PKE_UNUSED 128
1321 #define PKE_IBIT (PKE_UNUSED + 1)
1322 { 1, 31, TXVU_OPERAND_SUFFIX, parse_pke_ibit, 0, 0, print_pke_ibit },
1324 /* An 8 bit unsigned immediate, stored in upper 8 bits of immed field. */
1325 #define PKE_UIMM8UP (PKE_IBIT + 1)
1326 { 8, 8, 0, 0, 0, 0, 0 },
1328 /* An 8 bit unsigned immediate, stored in lower 8 bits of immed field. */
1329 #define PKE_UIMM8LO (PKE_UIMM8UP + 1)
1330 { 8, 0, 0, 0, 0, 0, 0 },
1332 /* An 16 bit unsigned immediate, stored in lower 8 bits of immed field. */
1333 #define PKE_UIMM16 (PKE_UIMM8LO + 1)
1334 { 16, 0, 0, 0, 0, 0, 0 },
1336 /* The mode operand of `stmod'. */
1337 #define PKE_MODE (PKE_UIMM16 + 1)
1338 { 2, 0, 0, parse_pke_mode, 0, 0, print_pke_mode },
1340 /* The ability operand of `mskpath3'. */
1341 #define PKE_ABILITY (PKE_MODE + 1)
1342 { 1, 15, 0, parse_pke_ability, 0, 0, print_pke_ability },
1345 #define PKE_VUADDR (PKE_ABILITY + 1)
1346 { 16, 0, 0, 0, 0, 0, 0 },
1348 /* A 32 bit immediate, appearing in 2nd,3rd,4th,5th words. */
1349 #define PKE_UIMM32 (PKE_VUADDR + 1)
1350 { 32, 0, 0, 0, 0, 0, 0 },
1352 /* VU address used by mpg insn. */
1353 #define PKE_MPGADDR (PKE_UIMM32 + 1)
1354 { 16, 0, TXVU_OPERAND_ADDRESS, parse_pke_mpgaddr, 0, 0, 0 },
1356 /* A variable length data specifier.
1357 Any of: file name, number, or '*'. */
1358 #define PKE_VARLENDATA (PKE_MPGADDR + 1)
1359 { 0, 0, 0, parse_pke_varlendata, 0, 0, 0 },
1361 /* The IMR bits of the unpack insn. */
1362 #define PKE_IMRBITS (PKE_VARLENDATA + 1)
1363 { 0, 0, TXVU_OPERAND_SUFFIX, parse_pke_imrbits, 0, 0, print_pke_imrbits },
1365 /* The type of the unpack insn. */
1366 #define PKE_UNPACKTYPE (PKE_IMRBITS + 1)
1367 { 4, 24, 0, parse_pke_unpacktype, 0, 0, print_pke_unpacktype },
1369 /* VU address used by unpack insn. */
1370 #define PKE_UNPACKADDR (PKE_UIMM32 + 1)
1371 { 16, 0, TXVU_OPERAND_ADDRESS, parse_pke_unpackaddr, 0, 0, 0 },
1373 /* Fake operand processed at end of parsing an insn to set the length. */
1375 /* end of list place holder */
1379 /* Field mask values. */
1380 #define MPKECMD 0x7f000000
1381 #define MPKEUNPACK 0x60000000
1384 #define VPKECMD(x) V ((x), 7, 24)
1385 #define VPKEUNPACK V (0x60, 8, 24)
1387 struct txvu_opcode pke_opcodes[] =
1389 { "pkenop", { PKE_IBIT }, 0x7fffffff, 0 },
1390 { "stcycle", { PKE_IBIT, SP, PKE_UIMM8UP, C, PKE_UIMM8LO }, MPKECMD, VPKECMD (1) },
1391 { "offset", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (2) },
1392 { "base", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (3) },
1393 { "itop", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (4) },
1394 { "stmod", { PKE_IBIT, SP, PKE_MODE }, MPKECMD + V (~0, 14, 2), VPKECMD (5) },
1395 { "mskpath3", { PKE_IBIT, SP, PKE_ABILITY }, MPKECMD + V (~0, 15, 0), VPKECMD (6) },
1396 { "pkemark", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (7) },
1397 { "flushe", { PKE_IBIT }, MPKECMD, VPKECMD (16) },
1398 { "flush", { PKE_IBIT }, MPKECMD, VPKECMD (17) },
1399 { "flusha", { PKE_IBIT }, MPKECMD, VPKECMD (19) },
1400 { "pkemscal", { PKE_IBIT, SP, PKE_VUADDR }, MPKECMD, VPKECMD (20) },
1401 { "pkemscnt", { PKE_IBIT }, MPKECMD, VPKECMD (23) },
1402 { "pkemscalf", { PKE_IBIT, SP, PKE_VUADDR }, MPKECMD, VPKECMD (21) },
1404 /* 2 word instructions */
1405 { "stmask", { PKE_IBIT, SP, PKE_UIMM32 }, MPKECMD, VPKECMD (32), PKE_OPCODE_LEN2 },
1407 /* 5 word instructions */
1408 { "strow", { PKE_IBIT, SP, PKE_UIMM32, C, PKE_UIMM32, C, PKE_UIMM32, C, PKE_UIMM32 }, MPKECMD, VPKECMD (48), PKE_OPCODE_LEN5 },
1409 { "stcol", { PKE_IBIT, SP, PKE_UIMM32, C, PKE_UIMM32, C, PKE_UIMM32, C, PKE_UIMM32 }, MPKECMD, VPKECMD (49), PKE_OPCODE_LEN5 },
1411 /* variable length instructions */
1412 { "mpg", { PKE_IBIT, SP, PKE_MPGADDR, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x4a), PKE_OPCODE_LENVAR + PKE_OPCODE_MPG },
1413 { "direct", { PKE_IBIT, SP, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x50), PKE_OPCODE_LENVAR + PKE_OPCODE_DIRECT },
1414 { "directhl", { PKE_IBIT, SP, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x51), PKE_OPCODE_LENVAR + PKE_OPCODE_DIRECT },
1415 { "unpack", { PKE_IMRBITS, SP, PKE_UNPACKTYPE, C, PKE_UNPACKADDR, C, PKE_VARLENDATA }, MPKEUNPACK, VPKEUNPACK, PKE_OPCODE_LENVAR + PKE_OPCODE_UNPACK },
1417 const int pke_opcodes_count = sizeof (pke_opcodes) / sizeof (pke_opcodes[0]);
1419 /* Non-zero if a variable length instruction was parsed. */
1420 static int state_pke_varlen_p;
1422 /* Length of parsed insn, in 32 bit words, or 0 if unknown. */
1423 static int state_pke_len;
1425 /* PKE parse,insert,extract,print helper fns. */
1428 parse_pke_ibit (opcode, operand, mods, pstr, errmsg)
1429 const txvu_opcode *opcode;
1430 const txvu_operand *operand;
1433 const char **errmsg;
1441 for (str = str + 1; *str != ']'; ++str)
1443 switch (tolower (*str))
1445 case 'i' : flags = 1; break;
1446 default : *errmsg = "unknown flag"; return 0;
1455 print_pke_ibit (opcode, operand, mods, insn, info, value)
1456 const txvu_opcode *opcode;
1457 const txvu_operand *operand;
1460 disassemble_info *info;
1464 (*info->fprintf_func) (info->stream, "[i]");
1467 static const keyword stmod_modes[] = {
1468 { PKE_MODE_DIRECT, "direct" },
1469 { PKE_MODE_ADD, "add" },
1470 { PKE_MODE_ADDROW, "addrow" },
1475 parse_pke_mode (opcode, operand, mods, pstr, errmsg)
1476 const txvu_opcode *opcode;
1477 const txvu_operand *operand;
1480 const char **errmsg;
1488 str = scan_symbol (str);
1491 mode = lookup_keyword_value (stmod_modes, start, 0);
1498 *errmsg = "invalid mode";
1503 print_pke_mode (opcode, operand, mods, insn, info, value)
1504 const txvu_opcode *opcode;
1505 const txvu_operand *operand;
1507 disassemble_info *info;
1511 const char *name = lookup_keyword_name (stmod_modes, value);
1514 (*info->fprintf_func) (info->stream, name);
1516 (*info->fprintf_func) (info->stream, "???");
1520 parse_pke_ability (opcode, operand, mods, pstr, errmsg)
1521 const txvu_opcode *opcode;
1522 const txvu_operand *operand;
1525 const char **errmsg;
1529 if (strncasecmp (str, "disable", 7) == 0)
1534 else if (strncasecmp (str, "enable", 6) == 0)
1539 *errmsg = "invalid ability";
1544 print_pke_ability (opcode, operand, mods, insn, info, value)
1545 const txvu_opcode *opcode;
1546 const txvu_operand *operand;
1549 disassemble_info *info;
1553 (*info->fprintf_func) (info->stream, "enable");
1555 (*info->fprintf_func) (info->stream, "disable");
1559 parse_pke_mpgaddr (opcode, operand, mods, pstr, errmsg)
1560 const txvu_opcode *opcode;
1561 const txvu_operand *operand;
1564 const char **errmsg;
1572 return 0; /* FIXME:indicate * somehow */
1576 str = strchr (str, ',');
1579 *errmsg = "invalid mpg address";
1583 /* FIXME: call back to expression() to parse address. */
1589 /* The result here is either the length specified,
1590 or PKE_VARLENDATA_FILE or PKE_VARLENDATA_UNKNOWN. */
1593 parse_pke_varlendata (opcode, operand, mods, pstr, errmsg)
1594 const txvu_opcode *opcode;
1595 const txvu_operand *operand;
1598 const char **errmsg;
1606 return 0; /* FIXME:indicate * somehow */
1611 /* FIXME: call back to expression() to parse address,
1612 and pick out filename if such. */
1614 *pstr = str + strlen (str);
1619 parse_pke_imrbits (opcode, operand, mods, pstr, errmsg)
1620 const txvu_opcode *opcode;
1621 const txvu_operand *operand;
1624 const char **errmsg;
1632 for (str = str + 1; *str != ']'; ++str)
1634 switch (tolower (*str))
1636 case 'i' : flags |= PKE_FLAG_I; break;
1637 case 'm' : flags |= PKE_FLAG_M; break;
1638 case 'r' : flags |= PKE_FLAG_R; break;
1639 default : *errmsg = "unknown pke flag"; return 0;
1648 print_pke_imrbits (opcode, operand, mods, insn, info, value)
1649 const txvu_opcode *opcode;
1650 const txvu_operand *operand;
1653 disassemble_info *info;
1658 (*info->fprintf_func) (info->stream, "[");
1659 if (value & PKE_FLAG_I)
1660 (*info->fprintf_func) (info->stream, "i");
1661 if (value & PKE_FLAG_M)
1662 (*info->fprintf_func) (info->stream, "m");
1663 if (value & PKE_FLAG_R)
1664 (*info->fprintf_func) (info->stream, "r");
1665 (*info->fprintf_func) (info->stream, "]");
1669 static const keyword unpack_types[] = {
1670 { PKE_UNPACK_S_32, "s_32" },
1671 { PKE_UNPACK_S_16, "s_16" },
1672 { PKE_UNPACK_S_8, "s_8" },
1673 { PKE_UNPACK_V2_32, "v2_32" },
1674 { PKE_UNPACK_V2_16, "v2_16" },
1675 { PKE_UNPACK_V2_8, "v2_8" },
1676 { PKE_UNPACK_V3_32, "v3_32" },
1677 { PKE_UNPACK_V3_16, "v3_16" },
1678 { PKE_UNPACK_V3_8, "v3_8" },
1679 { PKE_UNPACK_V4_32, "v4_32" },
1680 { PKE_UNPACK_V4_16, "v4_16" },
1681 { PKE_UNPACK_V4_8, "v4_8" },
1682 { PKE_UNPACK_V4_5, "v4_5" },
1687 parse_pke_unpacktype (opcode, operand, mods, pstr, errmsg)
1688 const txvu_opcode *opcode;
1689 const txvu_operand *operand;
1692 const char **errmsg;
1700 str = scan_symbol (str);
1703 type = lookup_keyword_value (unpack_types, start, 0);
1710 *errmsg = "invalid unpack type";
1715 print_pke_unpacktype (opcode, operand, mods, insn, info, value)
1716 const txvu_opcode *opcode;
1717 const txvu_operand *operand;
1720 disassemble_info *info;
1723 const char *name = lookup_keyword_name (unpack_types, value);
1726 (*info->fprintf_func) (info->stream, name);
1728 (*info->fprintf_func) (info->stream, "???");
1732 parse_pke_unpackaddr (opcode, operand, mods, pstr, errmsg)
1733 const txvu_opcode *opcode;
1734 const txvu_operand *operand;
1737 const char **errmsg;
1741 /* External PKE supporting routines. */
1743 /* Return non-zero if the just parsed pke insn has variable length. */
1748 /* This shouldn't be called unless a pke insn was parsed.
1749 Also, we want to catch errors in parsing that don't set this. */
1750 if (state_pke_varlen_p == -1)
1753 return state_pke_varlen_p;
1756 /* Return length, in 32 bit words, of just parsed pke insn,
1762 /* This shouldn't be called unless a pke insn was parsed.
1763 Also, we want to catch errors in parsing that don't set this. */
1764 if (state_pke_len == -1)
1767 return state_pke_len;
1772 PARSE_FN (dma_flags);
1773 INSERT_FN (dma_flags);
1774 EXTRACT_FN (dma_flags);
1775 PRINT_FN (dma_flags);
1777 PARSE_FN (dma_data);
1778 INSERT_FN (dma_data);
1779 EXTRACT_FN (dma_data);
1780 PRINT_FN (dma_data);
1782 PARSE_FN (dma_next);
1783 INSERT_FN (dma_next);
1784 EXTRACT_FN (dma_next);
1785 PRINT_FN (dma_next);
1787 const txvu_operand dma_operands[] =
1789 /* place holder (??? not sure if needed) */
1790 #define DMA_UNUSED 128
1793 /* dma tag flag bits */
1794 #define DMA_FLAGS (DMA_UNUSED + 1)
1795 { 0, 0, TXVU_OPERAND_SUFFIX,
1796 parse_dma_flags, insert_dma_flags, extract_dma_flags, print_dma_flags },
1799 #define DMA_DATA (DMA_FLAGS + 1)
1800 { 0, 0, TXVU_OPERAND_DMA_COUNT,
1801 0, insert_dma_data, extract_dma_data, print_dma_data },
1803 /* dma data finalization spec */
1804 #define DMA_DATA2 (DMA_DATA + 1)
1805 { 0, 0, TXVU_OPERAND_FAKE,
1806 parse_dma_data2, 0, 0, 0},
1808 /* dma next tag spec */
1809 #define DMA_ADDR (DMA_DATA2 + 1)
1811 parse_dma_addr, insert_dma_addr, extract_dma_addr, print_dma_addr},
1813 /* end of list place holder */
1817 struct txvu_opcode dma_opcodes[] =
1819 /* ??? Some of these may take optional arguments.
1820 The way to handle that is to have multiple table entries, those with and
1821 those without the optional arguments. */
1822 /*TODO*/ { "dmacall", { DMA_FLAGS, SP, DMA_DATA, C, DMA_ADDR}, 0, 1},
1823 /*TODO*/ { "dmacnt", { DMA_FLAGS, SP, DMA_DATA, C, DMA_ADDR}, 0, 2},
1824 { "dmaend", { DMA_FLAGS, SP, DMA_DATA, DMA_DATA2}, 0, 3},
1825 { "dmaend", { DMA_FLAGS, SP, DMA_DATA, C, DMA_ADDR}, 0, 4},
1826 /*TODO*/ { "dmanext", { DMA_FLAGS, SP, DMA_DATA, C, DMA_ADDR}, 0, 5},
1827 /*TODO { "dmaref", { DMA_FLAGS, SP, DMA_DATA, C, DMA_PTR_ADDR}, 0, 6}, */
1828 /*TODO { "dmarefs", { DMA_FLAGS, SP, DMA_DATA, C, DMA_PTR_ADDR}, 0, 7}, */
1829 /*TODO*/ { "dmaret", { DMA_FLAGS, SP, DMA_DATA, DMA_DATA2}, 0, 8}
1830 /*TODO*/ { "dmaret", { DMA_FLAGS, SP, DMA_DATA, C, DMA_ADDR}, 0, 9}
1832 const int dma_opcodes_count = sizeof (dma_opcodes) / sizeof (dma_opcodes[0]);
1834 /* Did the current DMA instruction has specify "*" as its length operand?
1835 -1=uninitialized, 0=no, 1=yes. */
1836 static int state_dma_operand_count_p;
1838 /* DMA parse,insert,extract,print helper fns. */
1841 parse_dma_flags (opcode, operand, mods, pstr, errmsg)
1842 const txvu_opcode *opcode;
1843 const txvu_operand *operand;
1846 const char **errmsg;
1854 for (str = str + 1; *str != ']'; ++str)
1856 switch (tolower (*str))
1858 case '0' : flags |= DMA_FLAG_PCE0; break;
1859 case '1' : flags |= DMA_FLAG_PCE1; break;
1860 case 'i' : flags |= DMA_FLAG_INT; break;
1861 case 's' : flags |= DMA_FLAG_SPR; break;
1862 default : *errmsg = "unknown dma flag"; return 0;
1871 insert_dma_flags (opcode, operand, mods, insn, value, errmsg)
1872 const txvu_opcode *opcode;
1873 const txvu_operand *operand;
1877 const char **errmsg;
1882 extract_dma_flags (opcode, operand, mods, insn, pinvalid)
1883 const txvu_opcode *opcode;
1884 const txvu_operand *operand;
1893 print_dma_flags (opcode, operand, mods, insn, info, value)
1894 const txvu_opcode *opcode;
1895 const txvu_operand *operand;
1898 disassemble_info *info;
1903 (*info->fprintf_func) (info->stream, "[");
1904 if (value & DMA_FLAG_PCE0)
1905 (*info->fprintf_func) (info->stream, "0");
1906 if (value & DMA_FLAG_PCE1)
1907 (*info->fprintf_func) (info->stream, "1");
1908 if (value & DMA_FLAG_INT)
1909 (*info->fprintf_func) (info->stream, "i");
1910 if (value & DMA_FLAG_SPR)
1911 (*info->fprintf_func) (info->stream, "s");
1912 (*info->fprintf_func) (info->stream, "]");
1917 parse_dma_data2( opcode, operand, mods, pstr, errmsg)
1918 const txvu_opcode *opcode;
1919 const txvu_operand *operand;
1922 const char **errmsg;
1925 If txvu_dma_operand_count() < 0 error
1926 if txvu_dma_operand_count() > 0
1927 if dmaref || dmarefs
1928 compute from two related symbols
1930 compute from current addr and end symbol
1931 store value to count field?
1936 insert_dma_data (opcode, operand, mods, insn, value, errmsg)
1937 const txvu_opcode *opcode;
1938 const txvu_operand *operand;
1942 const char **errmsg;
1947 extract_dma_data (opcode, operand, mods, insn, pinvalid)
1948 const txvu_opcode *opcode;
1949 const txvu_operand *operand;
1958 print_dma_data (opcode, operand, mods, insn, info, value)
1959 const txvu_opcode *opcode;
1960 const txvu_operand *operand;
1963 disassemble_info *info;
1966 (*info->fprintf_func) (info->stream, "???");
1970 parse_dma_addr (opcode, operand, mods, pstr, errmsg)
1971 const txvu_opcode *opcode;
1972 const txvu_operand *operand;
1975 const char **errmsg;
1977 char *start = *pstr;
1978 char *end = scan_symbol( start);
1982 *errmsg = "invalid dma next tag";
1986 /* FIXME: unfinished
1987 if txvu_dma_operand_count() > 0
1988 if dmaref || dmarefs
1989 this operand must be a symbol (vs an expression)
1991 store the symbol's value in the addr field (relocs?)
1992 compute the end_symbol's name
1993 lookup the end_symbol
1995 compute the length as _$<name>-<name>
1997 evaluate the operand as an expression
1998 store the value to the count field
1999 compute the length as _$EndDma-.
2000 store the count field
2002 evaluate the operand as an expression
2003 store the value to the count field
2006 parse_dma_data2( opcode, operand, mods, pstr, errmsg);
2013 insert_dma_addr (opcode, operand, mods, insn, value, errmsg)
2014 const txvu_opcode *opcode;
2015 const txvu_operand *operand;
2019 const char **errmsg;
2024 extract_dma_addr (opcode, operand, mods, insn, pinvalid)
2025 const txvu_opcode *opcode;
2026 const txvu_operand *operand;
2035 print_dma_addr (opcode, operand, mods, insn, info, value)
2036 const txvu_opcode *opcode;
2037 const txvu_operand *operand;
2040 disassemble_info *info;
2043 (*info->fprintf_func) (info->stream, "???");
2046 /* GPUIF support. */
2048 PARSE_FN (gpuif_prim);
2049 INSERT_FN (gpuif_prim);
2050 EXTRACT_FN (gpuif_prim);
2051 PRINT_FN (gpuif_prim);
2053 PARSE_FN (gpuif_regs);
2054 INSERT_FN (gpuif_regs);
2055 EXTRACT_FN (gpuif_regs);
2056 PRINT_FN (gpuif_regs);
2058 PARSE_FN (gpuif_nloop);
2059 INSERT_FN (gpuif_nloop);
2060 EXTRACT_FN (gpuif_nloop);
2061 PRINT_FN (gpuif_nloop);
2063 PARSE_FN (gpuif_eop);
2064 INSERT_FN (gpuif_eop);
2065 EXTRACT_FN (gpuif_eop);
2066 PRINT_FN (gpuif_eop);
2068 const txvu_operand gpuif_operands[] =
2070 /* place holder (??? not sure if needed) */
2071 #define GPUIF_UNUSED 128
2074 /* PRIM=foo operand */
2075 #define GPUIF_PRIM (GPUIF_UNUSED + 1)
2076 { 0, 0, 0, parse_gpuif_prim, insert_gpuif_prim, extract_gpuif_prim, print_gpuif_prim },
2078 /* REGS=foo operand */
2079 #define GPUIF_REGS (GPUIF_PRIM + 1)
2080 { 0, 0, 0, parse_gpuif_regs, insert_gpuif_regs, extract_gpuif_regs, print_gpuif_regs },
2082 /* NLOOP=foo operand */
2083 #define GPUIF_NLOOP (GPUIF_REGS + 1)
2084 { 0, 0, 0, parse_gpuif_nloop, insert_gpuif_nloop, extract_gpuif_nloop, print_gpuif_nloop },
2087 #define GPUIF_EOP (GPUIF_NLOOP + 1)
2088 { 0, 0, 0, parse_gpuif_eop, insert_gpuif_eop, extract_gpuif_eop, print_gpuif_eop },
2090 /* end of list place holder */
2094 struct txvu_opcode gpuif_opcodes[] =
2096 /* Some of these may take optional arguments.
2097 The way this is handled is to have multiple table entries, those with and
2098 those without the optional arguments.
2099 !!! The order here is important. The code that scans this table assumes
2100 that if it reaches the end of a syntax string there is nothing more to
2101 parse. This means that longer versions of instructions must appear before
2102 shorter ones. Otherwise the text at the "end" of a longer one may be
2103 interpreted as junk when the parser is using a shorter version of the
2106 { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
2107 { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
2108 { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
2109 { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
2110 { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
2111 { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
2112 { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS }, 0, 1 },
2113 { "gpuifpacked", { SP, GPUIF_REGS }, 0, 1 },
2115 { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 2 },
2116 { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 2 },
2117 { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 2 },
2118 { "gpuifreglist", { SP, GPUIF_REGS }, 0, 2 },
2120 { "gpuifimage", { SP, GPUIF_NLOOP }, 0, 3 },
2121 { "gpuifimage", { 0 }, 0, 3 },
2123 const int gpuif_opcodes_count = sizeof (gpuif_opcodes) / sizeof (gpuif_opcodes[0]);
2125 /* GPUIF parse,insert,extract,print helper fns. */
2128 parse_gpuif_prim (opcode, operand, mods, pstr, errmsg)
2129 const txvu_opcode *opcode;
2130 const txvu_operand *operand;
2133 const char **errmsg;
2139 if (strncasecmp (str, "prim=", 5) != 0)
2141 *errmsg = "missing PRIM spec";
2145 for (start = str; isalnum (*str); ++str)
2149 *errmsg = "missing PRIM spec";
2152 /* FIXME: Yes, atoi doesn't do error checking. Later. */
2153 prim = atoi (start);
2159 insert_gpuif_prim (opcode, operand, mods, insn, value, errmsg)
2160 const txvu_opcode *opcode;
2161 const txvu_operand *operand;
2165 const char **errmsg;
2170 extract_gpuif_prim (opcode, operand, mods, insn, pinvalid)
2171 const txvu_opcode *opcode;
2172 const txvu_operand *operand;
2181 print_gpuif_prim (opcode, operand, mods, insn, info, value)
2182 const txvu_opcode *opcode;
2183 const txvu_operand *operand;
2186 disassemble_info *info;
2189 (*info->fprintf_func) (info->stream, "???");
2192 static const keyword gpuif_regs[] = {
2193 { GPUIF_REG_PRIM, "prim" },
2194 { GPUIF_REG_RGBAQ, "rgbaq" },
2195 { GPUIF_REG_ST, "st" },
2196 { GPUIF_REG_UV, "uv" },
2197 { GPUIF_REG_XYZF2, "xyzf2" },
2198 { GPUIF_REG_TEXCLUT_1, "texclut_1" },
2199 { GPUIF_REG_TEXCLUT_2, "texclut_2" },
2200 { GPUIF_REG_TEX0_1, "tex0_1" },
2201 { GPUIF_REG_TEX0_2, "tex0_2" },
2202 { GPUIF_REG_TEX1_1, "tex1_1" },
2203 { GPUIF_REG_TEX1_2, "tex1_2" },
2204 { GPUIF_REG_XYZF3, "xyzf3" },
2205 { GPUIF_REG_PRMODE, "prmode" },
2206 { GPUIF_REG_A_D, "a_d" },
2207 { GPUIF_REG_NOP, "nop" },
2211 /* Parse a REGS= spec.
2212 The result is ???. */
2215 parse_gpuif_regs (opcode, operand, mods, pstr, errmsg)
2216 const txvu_opcode *opcode;
2217 const txvu_operand *operand;
2220 const char **errmsg;
2227 if (strncasecmp (str, "regs=", 5) != 0)
2229 *errmsg = "missing REGS spec";
2236 *errmsg = "missing '{' in REGS spec";
2241 while (*str && *str != '}')
2243 /* Pick out the register name. */
2247 str = scan_symbol (str);
2250 *errmsg = "invalid REG";
2254 /* Look it up in the table. */
2258 reg = lookup_keyword_value (gpuif_regs, start, 0);
2262 *errmsg = "invalid REG";
2266 /* FIXME: save `reg' away somewhere */
2268 /* Prepare for the next one. */
2273 else if (*str != '}')
2278 *errmsg = "missing '{' in REGS spec";
2283 return 0; /* FIXME */
2287 insert_gpuif_regs (opcode, operand, mods, insn, value, errmsg)
2288 const txvu_opcode *opcode;
2289 const txvu_operand *operand;
2293 const char **errmsg;
2298 extract_gpuif_regs (opcode, operand, mods, insn, pinvalid)
2299 const txvu_opcode *opcode;
2300 const txvu_operand *operand;
2309 print_gpuif_regs (opcode, operand, mods, insn, info, value)
2310 const txvu_opcode *opcode;
2311 const txvu_operand *operand;
2314 disassemble_info *info;
2317 (*info->fprintf_func) (info->stream, "???");
2321 parse_gpuif_nloop (opcode, operand, mods, pstr, errmsg)
2322 const txvu_opcode *opcode;
2323 const txvu_operand *operand;
2326 const char **errmsg;
2333 if (strncasecmp (str, "nloop=", 6) != 0)
2335 *errmsg = "missing NLOOP spec";
2341 str = scan_symbol (str);
2344 *errmsg = "invalid NOOP spec";
2347 /* FIXME: error checking */
2348 nloop = atoi (start);
2354 insert_gpuif_nloop (opcode, operand, mods, insn, value, errmsg)
2355 const txvu_opcode *opcode;
2356 const txvu_operand *operand;
2360 const char **errmsg;
2365 extract_gpuif_nloop (opcode, operand, mods, insn, pinvalid)
2366 const txvu_opcode *opcode;
2367 const txvu_operand *operand;
2376 print_gpuif_nloop (opcode, operand, mods, insn, info, value)
2377 const txvu_opcode *opcode;
2378 const txvu_operand *operand;
2381 disassemble_info *info;
2384 (*info->fprintf_func) (info->stream, "???");
2388 parse_gpuif_eop (opcode, operand, mods, pstr, errmsg)
2389 const txvu_opcode *opcode;
2390 const txvu_operand *operand;
2393 const char **errmsg;
2395 if (strncasecmp (*pstr, "eop", 3) == 0)
2400 *errmsg = "missing `EOP'";
2405 insert_gpuif_eop (opcode, operand, mods, insn, value, errmsg)
2406 const txvu_opcode *opcode;
2407 const txvu_operand *operand;
2411 const char **errmsg;
2416 extract_gpuif_eop (opcode, operand, mods, insn, pinvalid)
2417 const txvu_opcode *opcode;
2418 const txvu_operand *operand;
2427 print_gpuif_eop (opcode, operand, mods, insn, info, value)
2428 const txvu_opcode *opcode;
2429 const txvu_operand *operand;
2432 disassemble_info *info;
2435 (*info->fprintf_func) (info->stream, "???");
2439 These are called before doing each of the respective activities. */
2441 /* Called by the assembler before parsing an instruction. */
2444 txvu_opcode_init_parse ()
2446 state_vu_mnemonic_dest = -1;
2447 state_vu_mnemonic_bc = -1;
2448 state_pke_varlen_p = -1;
2450 state_dma_operand_count_p = -1;
2454 Query or set the current type of a DMA length operand, explicit or computed by "as".
2455 The return value is the setting before "action" is applied:
2456 -1=uninitialized, 0=explicit, +1=computed
2457 The value of "action" is interpreted as:
2458 -1=no change, 0=set explicit, +1=set computed
2461 txvu_dma_operand_count( action)
2463 int result = state_dma_operand_count;
2466 state_dma_operand_count = 0;
2467 else if( action > 0)
2468 state_dma_operand_count_p = 1;
2473 /* Called by the disassembler before printing an instruction. */
2476 txvu_opcode_init_print ()
2478 state_vu_mnemonic_dest = -1;
2479 state_vu_mnemonic_bc = -1;
2480 state_pke_varlen_p = -1;
2484 /* Indexed by first letter of opcode. Points to chain of opcodes with same
2486 /* ??? One can certainly use a better hash. Later. */
2487 static txvu_opcode *upper_opcode_map[26 + 1];
2488 static txvu_opcode *lower_opcode_map[26 + 1];
2490 /* Indexed by insn code. Points to chain of opcodes with same insn code. */
2491 static txvu_opcode *upper_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
2492 static txvu_opcode *lower_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
2494 /* Initialize any tables that need it.
2495 Must be called once at start up (or when first needed).
2497 FLAGS is currently unused but is intended to control initialization. */
2500 txvu_opcode_init_tables (flags)
2503 static int init_p = 0;
2505 /* We may be intentionally called more than once (for example gdb will call
2506 us each time the user switches cpu). These tables only need to be init'd
2508 /* ??? We can remove the need for txvu_opcode_supported by taking it into
2509 account here, but I'm not sure I want to do that yet (if ever). */
2514 /* Upper VU table. */
2516 memset (upper_opcode_map, 0, sizeof (upper_opcode_map));
2517 memset (upper_icode_map, 0, sizeof (upper_icode_map));
2518 /* Scan the table backwards so macros appear at the front. */
2519 for (i = txvu_upper_opcodes_count - 1; i >= 0; --i)
2521 int opcode_hash = TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes[i].mnemonic);
2522 int icode_hash = TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes[i].value);
2524 txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash];
2525 upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i];
2527 txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash];
2528 upper_icode_map[icode_hash] = &txvu_upper_opcodes[i];
2531 /* Lower VU table. */
2533 memset (lower_opcode_map, 0, sizeof (lower_opcode_map));
2534 memset (lower_icode_map, 0, sizeof (lower_icode_map));
2535 /* Scan the table backwards so macros appear at the front. */
2536 for (i = txvu_lower_opcodes_count - 1; i >= 0; --i)
2538 int opcode_hash = TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes[i].mnemonic);
2539 int icode_hash = TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes[i].value);
2541 txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash];
2542 lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i];
2544 txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash];
2545 lower_icode_map[icode_hash] = &txvu_lower_opcodes[i];
2548 /* FIXME: We just hash everything to the same value for the rest.
2549 Quick hack while other things are worked on. */
2553 for (i = pke_opcodes_count - 2; i >= 0; --i)
2555 pke_opcodes[i].next_asm = & pke_opcodes[i+1];
2556 pke_opcodes[i].next_dis = & pke_opcodes[i+1];
2561 for (i = dma_opcodes_count - 2; i >= 0; --i)
2563 dma_opcodes[i].next_asm = & dma_opcodes[i+1];
2564 dma_opcodes[i].next_dis = & dma_opcodes[i+1];
2569 for (i = gpuif_opcodes_count - 2; i >= 0; --i)
2571 gpuif_opcodes[i].next_asm = & gpuif_opcodes[i+1];
2572 gpuif_opcodes[i].next_dis = & gpuif_opcodes[i+1];
2579 /* Return the first insn in the chain for assembling upper INSN. */
2582 txvu_upper_opcode_lookup_asm (insn)
2585 return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)];
2588 /* Return the first insn in the chain for disassembling upper INSN. */
2591 txvu_upper_opcode_lookup_dis (insn)
2594 return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)];
2597 /* Return the first insn in the chain for assembling lower INSN. */
2600 txvu_lower_opcode_lookup_asm (insn)
2603 return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)];
2606 /* Return the first insn in the chain for disassembling lower INSN. */
2609 txvu_lower_opcode_lookup_dis (insn)
2612 return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)];
2615 /* Return the first insn in the chain for assembling lower INSN. */
2618 pke_opcode_lookup_asm (insn)
2621 return &pke_opcodes[0];
2624 /* Return the first insn in the chain for disassembling lower INSN. */
2627 pke_opcode_lookup_dis (insn)
2630 return &pke_opcodes[0];
2633 /* Return the first insn in the chain for assembling lower INSN. */
2636 dma_opcode_lookup_asm (insn)
2639 return &dma_opcodes[0];
2642 /* Return the first insn in the chain for disassembling lower INSN. */
2645 dma_opcode_lookup_dis (insn)
2648 return &dma_opcodes[0];
2651 /* Return the first insn in the chain for assembling lower INSN. */
2654 gpuif_opcode_lookup_asm (insn)
2657 return &gpuif_opcodes[0];
2660 /* Return the first insn in the chain for disassembling lower INSN. */
2663 gpuif_opcode_lookup_dis (insn)
2666 return &gpuif_opcodes[0];
2669 /* Misc. utilities. */
2671 /* Scan a symbol and return a pointer to one past the end. */
2677 while (*sym && issymchar (*sym))
2682 /* Given a keyword, look up its value, or -1 if not found. */
2685 lookup_keyword_value (table, name, case_sensitive_p)
2686 const keyword *table;
2688 int case_sensitive_p;
2692 if (case_sensitive_p)
2694 for (p = table; p->name; ++p)
2695 if (strcmp (name, p->name) == 0)
2700 for (p = table; p->name; ++p)
2701 if (strcasecmp (name, p->name) == 0)
2708 /* Given a keyword's value, look up its name, or NULL if not found. */
2711 lookup_keyword_name (table, value)
2712 const keyword *table;
2717 for (p = table; p->name; ++p)
2718 if (value == p->value)