d3a125c5762bf8e84c20d9b3d313e6e85561e034
[external/binutils.git] / opcodes / txvu-opc.c
1 /* Opcode table for the TXVU
2    Copyright 1998 Free Software Foundation, Inc.
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include "ansidecl.h"
19 #include "dis-asm.h"
20 #include "opcode/txvu.h"
21
22 #ifndef NULL
23 #define NULL 0
24 #endif
25
26 #if defined (__STDC__) || defined (ALMOST_STDC)
27 #define XCONCAT2(a,b)   a##b
28 #else
29 #define XCONCAT2(a,b)   a/**/b
30 #endif
31 #define CONCAT2(a,b)    XCONCAT2(a,b)
32
33 typedef struct {
34   int value;
35   const char *name;
36 } keyword;
37
38 static int lookup_keyword_value PARAMS ((const keyword *, const char *, int));
39 static const char *lookup_keyword_name PARAMS ((const keyword *table, int));
40
41 static char *scan_symbol PARAMS ((char *));
42
43 /* Return non-zero if CH is a character that may appear in a symbol.  */
44 /* FIXME: This will need revisiting.  */
45 #define issymchar(ch) (isalnum (ch) || ch == '_')
46
47 #define SKIP_BLANKS(var) while (isspace (*(var))) ++(var)
48
49 /* ??? One can argue it's preferable to have the PARSE_FN support in tc-vxvu.c
50    and the PRINT_FN support in txvu-dis.c.  For this project I like having
51    them all in one place.  */
52
53 #define PARSE_FN(fn) \
54 static long CONCAT2 (parse_,fn) \
55      PARAMS ((char **, const char **));
56 #define INSERT_FN(fn) \
57 static void CONCAT2 (insert_,fn) \
58      PARAMS ((TXVU_INSN *, const struct txvu_operand *, \
59               int, long, const char **))
60 #define EXTRACT_FN(fn) \
61 static long CONCAT2 (extract_,fn) \
62      PARAMS ((TXVU_INSN *, const struct txvu_operand *, \
63               int, int *))
64 #define PRINT_FN(fn) \
65 static void CONCAT2 (print_,fn) \
66      PARAMS ((disassemble_info *, TXVU_INSN *, long));
67
68 PARSE_FN (dotdest);
69 INSERT_FN (dotdest);
70 EXTRACT_FN (dotdest);
71 PRINT_FN (dotdest);
72
73 PARSE_FN (dotdest1);
74 PARSE_FN (dest1);
75 PRINT_FN (dest1);
76
77 PARSE_FN (bc);
78 EXTRACT_FN (bc);
79 PRINT_FN (sdest);
80
81 PARSE_FN (vfreg);
82 PRINT_FN (vfreg);
83
84 PARSE_FN (bcftreg);
85 PRINT_FN (bcftreg);
86
87 PARSE_FN (accdest);
88 PRINT_FN (accdest);
89
90 INSERT_FN (xyz);
91
92 PARSE_FN (ireg);
93 PRINT_FN (ireg);
94
95 PARSE_FN (freg);
96 PRINT_FN (freg);
97
98 PARSE_FN (ffstreg);
99 INSERT_FN (ffstreg);
100 EXTRACT_FN (ffstreg);
101 PRINT_FN (ffstreg);
102
103 PARSE_FN (vi01);
104 PRINT_FN (vi01);
105
106 INSERT_FN (luimm12);
107 EXTRACT_FN (luimm12);
108
109 INSERT_FN (luimm12up6);
110
111 INSERT_FN (luimm15);
112 EXTRACT_FN (luimm15);
113
114 /* Various types of TXVU operands, including insn suffixes.
115
116    Fields are:
117
118    BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
119
120    Operand values are 128 + table index.  This allows ASCII chars to be
121    included in the syntax spec.  */
122
123 const struct txvu_operand txvu_operands[] =
124 {
125   /* place holder (??? not sure if needed) */
126 #define UNUSED 128
127   { 0 },
128
129   /* Operands that exist in the same place for essentially the same purpose
130      in both upper and lower instructions.  These don't have a U or L prefix.
131      Operands specific to the upper or lower instruction are so prefixed.  */
132
133   /* Destination indicator attached to mnemonic, with leading '.' or '/'.
134      After parsing this, the value is stored in global `dest' so that the
135      register parser can verify the same choice of xyzw is used.  */
136 #define DOTDEST (UNUSED + 1)
137   { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
138       parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest },
139
140   /* ft reg, with vector specification same as DOTDEST */
141 #define VFTREG (DOTDEST + 1)
142   { 5, TXVU_SHIFT_TREG, 0, parse_vfreg, 0, 0, print_vfreg },
143
144   /* fs reg, with vector specification same as DOTDEST */
145 #define VFSREG (VFTREG + 1)
146   { 5, TXVU_SHIFT_SREG, 0, parse_vfreg, 0, 0, print_vfreg },
147
148   /* fd reg, with vector specification same as DOTDEST */
149 #define VFDREG (VFSREG + 1)
150   { 5, TXVU_SHIFT_DREG, 0, parse_vfreg, 0, 0, print_vfreg },
151
152   /* Upper word operands.  */
153
154   /* broadcast */
155 #define UBC (VFDREG + 1)
156   { 2, 0, TXVU_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest },
157
158   /* ftreg in broadcast case */
159 #define UBCFTREG (UBC + 1)
160   { 5, TXVU_SHIFT_TREG, 0, parse_bcftreg, 0, 0, print_bcftreg },
161
162   /* accumulator dest */
163 #define UACCDEST (UBCFTREG + 1)
164   { 0, 0, 0, parse_accdest, 0, 0, print_accdest },
165
166   /* The XYZ operand is a fake one that is used to ensure only "xyz" is
167      specified.  It simplifies the opmula and opmsub entries.  */
168 #define UXYZ (UACCDEST + 1)
169   { 0, 0, TXVU_OPERAND_FAKE, 0, insert_xyz, 0, 0 },
170
171   /* Lower word operands.  */
172
173   /* 5 bit signed immediate.  */
174 #define LIMM5 (UXYZ + 1)
175   { 5, 6, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
176
177   /* 11 bit signed immediate.  */
178 #define LIMM11 (LIMM5 + 1)
179   { 11, 0, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
180
181   /* 15 bit unsigned immediate.  */
182 #define LUIMM15 (LIMM11 + 1)
183   { 15, 0, 0, 0, insert_luimm15, extract_luimm15, 0 },
184
185   /* ID register.  */
186 #define LIDREG (LUIMM15 + 1)
187   { 5, 6, 0, parse_ireg, 0, 0, print_ireg },
188
189   /* IS register.  */
190 #define LISREG (LIDREG + 1)
191   { 5, 11, 0, parse_ireg, 0, 0, print_ireg },
192
193   /* IT register.  */
194 #define LITREG (LISREG + 1)
195   { 5, 16, 0, parse_ireg, 0, 0, print_ireg },
196
197   /* FS reg, with FSF field selector.  */
198 #define LFSFFSREG (LITREG + 1)
199   { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
200
201   /* FS reg, no selector (choice of x,y,z,w is provided by opcode).  */
202 #define LFSREG (LFSFFSREG + 1)
203   { 5, 11, 0, parse_freg, 0, 0, print_freg },
204
205   /* FT reg, with FTF field selector.  */
206 #define LFTFFTREG (LFSREG + 1)
207   { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
208
209   /* VI01 register.  */
210 #define LVI01 (LFTFFTREG + 1)
211   { 0, 0, 0, parse_vi01, 0, 0, print_vi01 },
212
213   /* 24 bit unsigned immediate.  */
214 #define LUIMM24 (LVI01 + 1)
215   { 24, 0, 0, 0, 0, 0, 0 },
216
217   /* 12 bit unsigned immediate, split into 1 and 11 bit pieces.  */
218 #define LUIMM12 (LUIMM24 + 1)
219   { 12, 0, 0, 0, insert_luimm12, extract_luimm12, 0 },
220
221   /* upper 6 bits of 12 bit unsigned immediate */
222 #define LUIMM12UP6 (LUIMM12 + 1)
223   { 12, 0, 0, 0, insert_luimm12up6, extract_luimm12, 0 },
224
225   /* 11 bit pc-relative signed immediate.  */
226 #define LPCREL11 (LUIMM12UP6 + 1)
227   { 11, 0, TXVU_OPERAND_SIGNED + TXVU_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 },
228
229   /* Destination indicator, single letter only, with leading '.'.  */
230 #define LDOTDEST1 (LPCREL11 + 1)
231   { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
232       /* Note that we borrow the insert/extract/print functions from the
233          vector case.  */
234       parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
235
236   /* Destination indicator, single letter only, no leading '.'.  */
237 #define LDEST1 (LDOTDEST1 + 1)
238   { 0, 0, 0, parse_dest1, 0, 0, print_dest1 },
239
240 /* end of list place holder */
241   { 0 }
242 };
243 \f
244 /* Macros to put a field's value into the right place.  */
245 /* ??? If assembler needs these, move to opcode/txvu.h.  */
246
247 /* value X, B bits, shift S */
248 #define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s))
249
250 /* Field value macros for both upper and lower instructions.
251    These shift a value into the right place in the instruction.  */
252
253 /* [FI] T reg field (remember it's V for value, not vector, here).  */
254 #define VT(x) V ((x), 5, TXVU_SHIFT_TREG)
255 /* [FI] S reg field.  */
256 #define VS(x) V ((x), 5, TXVU_SHIFT_SREG)
257 /* [FI] D reg field.  */
258 #define VD(x) V ((x), 5, TXVU_SHIFT_DREG)
259 /* DEST field.  */
260 #define VDEST(x) V ((x), 4, 21)
261
262 /* Masks for fields in both upper and lower instructions.
263    These mask out all bits but the ones for the field in the instruction.  */
264
265 #define MT VT (~0)
266 #define MS VS (~0)
267 #define MD VD (~0)
268 #define MDEST VDEST (~0)
269
270 /* Upper instruction Value macros.  */
271
272 /* Upper Flag bits.  */
273 #define VUF(x) V ((x), 5, 27)
274 /* Upper REServed two bits next to flag bits.  */
275 #define VURES(x) V ((x), 2, 25)
276 /* 4 bit opcode field.  */
277 #define VUOP4(x) V ((x), 4, 2)
278 /* 6 bit opcode field.  */
279 #define VUOP6(x) V ((x), 6, 0)
280 /* 9 bit opcode field.  */
281 #define VUOP9(x) V ((x), 9, 2)
282 /* 11 bit opcode field.  */
283 #define VUOP11(x) V ((x), 11, 0)
284 /* BroadCast field.  */
285 #define VUBC(x) V ((x), 2, 0)
286
287 /* Upper instruction field masks.  */
288 #define MUUBITS (VUF (~0) + VURES (~0))
289 #define MURES VURES (~0)
290 #define MUOP4 VUOP4 (~0)
291 #define MUOP6 VUOP6 (~0)
292 #define MUOP9 VUOP9 (~0)
293 #define MUOP11 VUOP11 (~0)
294
295 /* A space, separates instruction name (mnemonic + mnemonic operands) from
296    operands.  */
297 #define SP ' '
298 /* Commas separate operands.  */
299 #define C ','
300 /* Special I,P,Q,R operands.  */
301 #define I 'i'
302 #define P 'p'
303 #define Q 'q'
304 #define R 'r'
305
306 /* TXVU instructions.
307    [??? some of these comments are left over from the ARC port from which
308    this code is borrowed, delete in time]
309
310    Longer versions of insns must appear before shorter ones (if gas sees
311    "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
312    junk).  This isn't necessary for `ld' because of the trailing ']'.
313
314    Instructions that are really macros based on other insns must appear
315    before the real insn so they're chosen when disassembling.  Eg: The `mov'
316    insn is really the `and' insn.
317
318    This table is best viewed on a wide screen (161 columns).  I'd prefer to
319    keep it this way.  The rest of the file, however, should be viewable on an
320    80 column terminal.  */
321
322 /* ??? This table also includes macros: asl, lsl, and mov.  The ppc port has
323    a more general facility for dealing with macros which could be used if
324    we need to.  */
325
326 /* These tables can't be `const' because members `next_asm' and `next_dis' are
327    computed at run-time.  We could split this into two, as that would put the
328    constant stuff into a readonly section.  */
329
330 struct txvu_opcode txvu_upper_opcodes[] =
331 {
332   /* Macros appear first, so the disassembler will try them first.  */
333   /* ??? Any aliases?  */
334   /* ??? When close to being finished, clean up by aligning fields.  */
335
336   /* The rest of these needn't be sorted, but it helps to find them if they are.  */
337   { "abs", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x1fd) },
338   { "add", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x28) },
339   { "addi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x22) },
340   { "addq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x20) },
341   { "add", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (0) },
342   { "adda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bc) },
343   { "addai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23e) },
344   { "addaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23c) },
345   { "adda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0xf) },
346   { "clip", { DOTDEST, SP, VFSREG }, MURES + MDEST + MT + MUOP11, VDEST (0xf) + VUOP11 (0x1ff) },
347   { "ftoi0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17c) },
348   { "ftoi4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17d) },
349   { "ftoi12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17e) },
350   { "ftoi15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17f) },
351   { "itof0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13c) },
352   { "itof4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13d) },
353   { "itof12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13e) },
354   { "itof15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13f) },
355   { "madd", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x29) },
356   { "maddi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x23) },
357   { "maddq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x21) },
358   { "madd", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x2) },
359   { "madda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bd) },
360   { "maddai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23f) },
361   { "maddaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23d) },
362   { "madda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x2f) },
363   { "max", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2b) },
364   { "maxi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x2d) },
365   { "max", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x4) },
366   /* ??? mini or min? */
367   { "mini", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2f) },
368   { "minii", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1f) },
369   { "mini", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x5) },
370   { "msub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2d) },
371   { "msubi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x27) },
372   { "msubq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x25) },
373   { "msub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x3) },
374   { "msuba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fd) },
375   { "msubai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27f) },
376   { "msubaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27d) },
377   { "msuba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x3f) },
378   { "mul", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2a) },
379   { "muli", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1e) },
380   { "mulq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x1c) },
381   { "mul", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (6) },
382   { "mula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2be) },
383   { "mulai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x1fe) },
384   { "mulaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x1fc) },
385   { "mula", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x6f) },
386   { "nop", { 0 }, MURES + MDEST + MT + MS + MUOP11, VUOP11 (0x2ff) },
387   { "opmula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP11, VUOP11 (0x2fe) },
388   { "opmsub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP6, VUOP6 (0x2e) },
389   { "sub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2c) },
390   { "subi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x26) },
391   { "subq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x24) },
392   { "sub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (1) },
393   { "suba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fc) },
394   { "subai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27e) },
395   { "subaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27c) },
396   { "suba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x1f) }
397 };
398 const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_upper_opcodes[0]);
399 \f
400 /* Lower instruction Value macros.  */
401
402 /* 6 bit opcode.  */
403 #define VLOP6(x) V ((x), 6, 0)
404 /* 7 bit opcode.  */
405 #define VLOP7(x) V ((x), 7, 25)
406 /* 11 bit opcode.  */
407 #define VLOP11(x) V ((x), 11, 0)
408 /* 11 bit immediate.  */
409 #define VLIMM11(x) V ((x), 11, 0)
410 /* FTF field.  */
411 #define VLFTF(x) V ((x), 2, 23)
412 /* FSF field.  */
413 #define VLFSF(x) V ((x), 2, 21)
414 /* Upper bit of 12 bit unsigned immediate.  */
415 #define VLUIMM12TOP(x) V ((x), 1, 21)
416 /* Upper 4 bits of 15 bit unsigned immediate.  */
417 #define VLUIMM15TOP(x) VDEST (x)
418
419 /* Lower instruction field masks.  */
420 #define MLOP6 VLOP6 (~0)
421 #define MLOP7 VLOP7 (~0)
422 #define MLOP11 VLOP11 (~0)
423 #define MLIMM11 VLIMM11 (~0)
424 #define MLB24 V (1, 1, 24)
425 #define MLUIMM12TOP VLUIMM12TOP (~0)
426 /* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits.
427    The upper 1 bit is part of the `dest' field.  This mask is for the
428    other 3 bits of the dest field.  */
429 #define MLUIMM12UNUSED V (7, 3, 22)
430 #define MLUIMM15TOP MDEST
431
432 struct txvu_opcode txvu_lower_opcodes[] =
433 {
434   /* Macros appear first, so the disassembler will try them first.  */
435   /* ??? Any aliases?  */
436   /* ??? There isn't an explicit nop.  Apparently it's "move vf0,vf0".  */
437   { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) },
438
439   /* The rest of these needn't be sorted, but it helps to find them if they are.  */
440   { "b", { SP, LPCREL11 }, MLOP7 + MDEST + MT + MS, VLOP7 (0x20) },
441   { "bal", { SP, LITREG, C, LPCREL11 }, MLOP7 + MDEST + MS, VLOP7 (0x21) },
442   { "div", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLOP11, VLOP7 (0x40) + VLOP11 (0x3bc) },
443   { "eatan", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) },
444   { "eatanxy", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77c) },
445   { "eatanxz", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77d) },
446   { "eexp", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) },
447   { "eleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x74e) },
448   { "ercpr", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) },
449   { "erleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73f) },
450   { "ersadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73d) },
451   { "ersqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) },
452   { "esadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73c) },
453   { "esin", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) },
454   { "esqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) },
455   { "esum", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) },
456   { "fcand", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x12) },
457   { "fceq", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) },
458   { "fcget", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x1c) },
459   { "fcor", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) },
460   { "fcset", { SP, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) },
461   { "fmand", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1a) },
462   { "fmeq", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x18) },
463   { "fmor", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1b) },
464   { "fsand", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x16) },
465   { "fseq", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x14) },
466   { "fsor", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x17) },
467   { "fsset", { SP, LUIMM12UP6 }, MLOP7 + MLUIMM12UNUSED + V (~0, 6, 0) + MS + MT, VLOP7 (0x15) },
468   { "iadd", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x30) },
469   { "iaddi", { SP, LITREG, C, LISREG, C, LIMM5 }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x32) },
470   { "iaddiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x08) },
471   { "iand", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
472   { "ibeq", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x28) },
473   { "ibgez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2f) },
474   { "ibgtz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2d) },
475   { "iblez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2e) },
476   { "ibltz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2c) },
477   { "ibne", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x29) },
478   { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x04) },
479   { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fe) },
480   { "ior", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
481   { "isub", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x31) },
482   { "isubiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x09) },
483   { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x05) },
484   { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3ff) },
485   { "jalr", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x25) },
486   { "jr", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x24) },
487   { "lq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x00) },
488   { "lqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37e) },
489   { "lqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37c) },
490   /* Only a single VF reg is allowed here.  We can use VFTREG because LDOTDEST1
491      handles verifying only a single choice of xyzw is present.  */
492   { "mfir", { LDOTDEST1, SP, VFTREG, C, LISREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fc) },
493   { "mfp", { DOTDEST, SP, VFTREG, C, P }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x67c) },
494   { "move", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33c) },
495   { "mr32", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33d) },
496   { "mtir", { LDOTDEST1, SP, LITREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) },
497   { "rget", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43d) },
498   { "rinit", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) },
499   { "rnext", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43c) },
500   { "rsqrt", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3be) },
501   { "rxor", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
502   { "sq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x01) },
503   { "sqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37f) },
504   { "sqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37d) },
505   { "sqrt", { SP, Q, C, LFTFFTREG }, MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) },
506   { "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) },
507   { "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) },
508   { "xgkick", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) },
509   { "xitop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) },
510   { "xtop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) }
511 };
512 const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]);
513 \f
514 /* Value of DEST in use.
515    Each of the registers must specify the same value as the opcode.
516    ??? Perhaps remove the duplication?  */
517 static int mnemonic_dest;
518
519 /* Value of BC to use.
520    The register specified for the ftreg must match the broadcast register
521    specified in the opcode.  */
522 static int mnemonic_bc;
523 \f
524 /* Multiple destination choice support.
525    The "dest" string selects any combination of x,y,z,w.
526    [The letters are ordered that way to follow the manual's style.]  */
527
528 /* Utility to parse a `dest' spec.
529    Return the found value.
530    *PSTR is set to the character that terminated the parsing.
531    It is up to the caller to do any error checking.  */
532
533 static long
534 _parse_dest (pstr)
535      char **pstr;
536 {
537   long dest = 0;
538
539   while (**pstr)
540     {
541       switch (**pstr)
542         {
543         case 'x' : case 'X' : dest |= TXVU_DEST_X; break;
544         case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break;
545         case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break;
546         case 'w' : case 'W' : dest |= TXVU_DEST_W; break;
547         default : return dest;
548         }
549       ++*pstr;
550     }
551
552   return dest;
553 }
554
555 static long
556 parse_dotdest (pstr, errmsg)
557      char **pstr;
558      const char **errmsg;
559 {
560   long dest;
561
562   if (**pstr != '.')
563     {
564       *errmsg = "missing `.'";
565       return 0;
566     }
567
568   ++*pstr;
569   dest = _parse_dest (pstr);
570   if (dest == 0 || isalnum (**pstr))
571     {
572       *errmsg = "invalid `dest'";
573       return 0;
574     }
575
576   return dest;
577 }
578
579 /* Parse a `dest' spec where only a single letter is allowed,
580    but the encoding handles all four.  */
581
582 static long
583 parse_dotdest1 (pstr, errmsg)
584      char **pstr;
585      const char **errmsg;
586 {
587   char c;
588   long dest;
589
590   if (**pstr != '.')
591     {
592       *errmsg = "missing `.'";
593       return 0;
594     }
595
596   ++*pstr;
597   switch (**pstr)
598     {
599     case 'x' : case 'X' : dest = TXVU_DEST_X; break;
600     case 'y' : case 'Y' : dest = TXVU_DEST_Y; break;
601     case 'z' : case 'Z' : dest = TXVU_DEST_Z; break;
602     case 'w' : case 'W' : dest = TXVU_DEST_W; break;
603     default : *errmsg = "invalid `dest'"; return 0;
604     }
605   ++*pstr;
606   c = tolower (**pstr);
607   if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
608     {
609       *errmsg = "only one of x,y,z,w can be specified";
610       return 0;
611     }
612   if (isalnum (**pstr))
613     {
614       *errmsg = "invalid `dest'";
615       return 0;
616     }
617
618   return dest;
619 }
620
621 /* Parse a `dest' spec with no leading '.', where only a single letter is
622    allowed, but the encoding handles all four.  The parsed value must match
623    that recorded in `dest'.  */
624
625 static long
626 parse_dest1 (pstr, errmsg)
627      char **pstr;
628      const char **errmsg;
629 {
630   char c;
631   long dest;
632
633   dest = _parse_dest (pstr);
634   if (dest != TXVU_DEST_X
635       && dest != TXVU_DEST_Y
636       && dest != TXVU_DEST_Z
637       && dest != TXVU_DEST_W)
638     {
639       *errmsg = "expecting one of x,y,z,w";
640       return 0;
641     }
642
643   if (dest != mnemonic_dest)
644     {
645       *errmsg = "`dest' suffix does not match instruction `dest'";
646       return 0;
647     }
648
649   return dest;
650 }
651
652 static void
653 insert_dotdest (insn, operand, mods, value, errmsg)
654      TXVU_INSN *insn;
655      const struct txvu_operand *operand;
656      int mods;
657      long value;
658      const char **errmsg;
659 {
660   /* Record the DEST value in use so the register parser can use it.  */
661   mnemonic_dest = value;
662   *insn |= value << operand->shift;
663 }
664
665 static long
666 extract_dotdest (insn, operand, mods, pinvalid)
667      TXVU_INSN *insn;
668      const struct txvu_operand *operand;
669      int mods;
670      int *pinvalid;
671 {
672   /* Record the DEST value in use so the register printer can use it.  */
673   mnemonic_dest = (*insn >> operand->shift) & ((1 << operand->bits) - 1);
674   return mnemonic_dest;
675 }
676
677 /* Utility to print a multiple dest spec.  */
678
679 static void
680 _print_dest (info, insn, value)
681      disassemble_info *info;
682      TXVU_INSN *insn;
683      long value;
684 {
685   if (value & TXVU_DEST_X)
686     (*info->fprintf_func) (info->stream, "x");
687   if (value & TXVU_DEST_Y)
688     (*info->fprintf_func) (info->stream, "y");
689   if (value & TXVU_DEST_Z)
690     (*info->fprintf_func) (info->stream, "z");
691   if (value & TXVU_DEST_W)
692     (*info->fprintf_func) (info->stream, "w");
693 }
694
695 static void
696 print_dotdest (info, insn, value)
697      disassemble_info *info;
698      TXVU_INSN *insn;
699      long value;
700 {
701   (*info->fprintf_func) (info->stream, ".");
702   _print_dest (info, insn, value);
703 }
704
705 static void
706 print_dest1 (info, insn, value)
707      disassemble_info *info;
708      TXVU_INSN *insn;
709      long value;
710 {
711   _print_dest (info, insn, mnemonic_dest);
712 }
713 \f
714 /* Utilities for single destination choice handling.  */
715
716 static long
717 _parse_sdest (pstr, errmsg)
718      char **pstr;
719      const char **errmsg;
720 {
721   char c;
722   long dest = 0;
723
724   switch (**pstr)
725     {
726     case 'x' : case 'X' : dest = TXVU_SDEST_X; break;
727     case 'y' : case 'Y' : dest = TXVU_SDEST_Y; break;
728     case 'z' : case 'Z' : dest = TXVU_SDEST_Z; break;
729     case 'w' : case 'W' : dest = TXVU_SDEST_W; break;
730     default : *errmsg = "only one of x,y,z,w can be specified"; return 0;
731     }
732   ++*pstr;
733   c = tolower (**pstr);
734   if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
735     {
736       *errmsg = "only one of x,y,z,w can be specified";
737       return 0;
738     }
739   if (isalnum (**pstr))
740     {
741       *errmsg = "invalid `dest'";
742       return 0;
743     }
744
745   return dest;
746 }
747
748 static void
749 print_sdest (info, insn, value)
750      disassemble_info *info;
751      TXVU_INSN *insn;
752      long value;
753 {
754   char c;
755
756   switch (value)
757     {
758     case TXVU_SDEST_X : c = 'x'; break;
759     case TXVU_SDEST_Y : c = 'y'; break;
760     case TXVU_SDEST_Z : c = 'z'; break;
761     case TXVU_SDEST_W : c = 'w'; break;
762     }
763
764   (*info->fprintf_func) (info->stream, "%c", c);
765 }
766 \f
767 /* Broadcase field.  */
768
769 static long
770 parse_bc (pstr, errmsg)
771      char **pstr;
772      const char **errmsg;
773 {
774   long value = _parse_sdest (pstr, errmsg);
775
776   if (*errmsg)
777     return 0;
778   /* Save value for later verification in register parsing.  */
779   mnemonic_bc = value;
780   return value;
781 }
782
783 /* During the extraction process, save the bc field for use in
784    printing the bc register.  */
785
786 static long
787 extract_bc (insn, operand, mods, pinvalid)
788      TXVU_INSN *insn;
789      const struct txvu_operand *operand;
790      int mods;
791      int *pinvalid;
792 {
793   mnemonic_bc = *insn & 3;
794   return mnemonic_bc;
795 }
796 \f
797 static long
798 parse_vfreg (pstr, errmsg)
799      char **pstr;
800      const char **errmsg;
801 {
802   char *str = *pstr;
803   char *start;
804   long reg;
805   int reg_dest;
806
807   if (tolower (str[0]) != 'v'
808       || tolower (str[1]) != 'f')
809     {
810       *errmsg = "unknown register";
811       return 0;
812     }
813
814   /* FIXME: quick hack until the framework works.  */
815   start = str = str + 2;
816   while (*str && isdigit (*str))
817     ++str;
818   reg = atoi (start);
819   if (reg < 0 || reg > 31)
820     {
821       *errmsg = "invalid register number";
822       return 0;
823     }
824   reg_dest = _parse_dest (&str);
825   if (reg_dest == 0 || isalnum (*str))
826     {
827       *errmsg = "invalid `dest'";
828       return 0;
829     }
830   if (reg_dest != mnemonic_dest)
831     {
832       *errmsg = "register `dest' does not match instruction `dest'";
833       return 0;
834     }
835   *pstr = str;
836   return reg;
837 }
838
839 static void
840 print_vfreg (info, insn, value)
841      disassemble_info *info;
842      TXVU_INSN *insn;
843      long value;
844 {
845   (*info->fprintf_func) (info->stream, "vf%02ld", value);
846   _print_dest (info, insn, mnemonic_dest);
847 }
848 \f
849 /* FT register in broadcast case.  */
850
851 static long
852 parse_bcftreg (pstr, errmsg)
853      char **pstr;
854      const char **errmsg;
855 {
856   char *str = *pstr;
857   char *start;
858   long reg;
859   int reg_bc;
860
861   if (tolower (str[0]) != 'v'
862       || tolower (str[1]) != 'f')
863     {
864       *errmsg = "unknown register";
865       return 0;
866     }
867
868   /* FIXME: quick hack until the framework works.  */
869   start = str = str + 2;
870   while (*str && isdigit (*str))
871     ++str;
872   reg = atoi (start);
873   if (reg < 0 || reg > 31)
874     {
875       *errmsg = "invalid register number";
876       return 0;
877     }
878   reg_bc = _parse_sdest (&str, errmsg);
879   if (*errmsg)
880     return 0;
881   if (reg_bc != mnemonic_bc)
882     {
883       *errmsg = "register `bc' does not match instruction `bc'";
884       return 0;
885     }
886   *pstr = str;
887   return reg;
888 }
889
890 static void
891 print_bcftreg (info, insn, value)
892      disassemble_info *info;
893      TXVU_INSN *insn;
894      long value;
895 {
896   (*info->fprintf_func) (info->stream, "vf%02ld", value);
897   print_sdest (info, insn, mnemonic_bc);
898 }
899 \f
900 /* ACC handling.  */
901
902 static long
903 parse_accdest (pstr, errmsg)
904      char **pstr;
905      const char **errmsg;
906 {
907   char *str = *pstr;
908   long acc_dest = 0;
909
910   if (strncasecmp (str, "acc", 3) != 0)
911     {
912       *errmsg = "expecting `acc'";
913       return 0;
914     }
915   str += 3;
916   acc_dest = _parse_dest (&str);
917   if (acc_dest == 0 || isalnum (*str))
918     {
919       *errmsg = "invalid `dest'";
920       return 0;
921     }
922   if (acc_dest != mnemonic_dest)
923     {
924       *errmsg = "acc `dest' does not match instruction `dest'";
925       return 0;
926     }
927   *pstr = str;
928   /* Value isn't used, but we must return something.  */
929   return 0;
930 }
931
932 static void
933 print_accdest (info, insn, value)
934      disassemble_info *info;
935      TXVU_INSN *insn;
936      long value;
937 {
938   (*info->fprintf_func) (info->stream, "acc");
939   _print_dest (info, insn, mnemonic_dest);
940 }
941 \f
942 /* XYZ operand handling.
943    This simplifies the opmula,opmsub entries by keeping them equivalent to
944    the others.  */
945
946 static void
947 insert_xyz (insn, operand, mods, value, errmsg)
948      TXVU_INSN *insn;
949      const struct txvu_operand *operand;
950      int mods;
951      long value;
952      const char **errmsg;
953 {
954   if (mnemonic_dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
955     *errmsg = "expecting `xyz' for `dest' value";
956 }
957 \f
958 /* F[ST] register using selector in F[ST]F field.
959    Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator
960    followed by the 5 bit register number.  */
961
962 static long
963 parse_ffstreg (pstr, errmsg)
964      char **pstr;
965      const char **errmsg;
966 {
967   char *str = *pstr;
968   char *start;
969   int reg, xyzw;
970
971   if (tolower (str[0]) != 'v'
972       || tolower (str[1]) != 'f')
973     {
974       *errmsg = "unknown register";
975       return 0;
976     }
977
978   /* FIXME: quick hack until the framework works.  */
979   start = str = str + 2;
980   while (*str && isdigit (*str))
981     ++str;
982   reg = atoi (start);
983   if (reg < 0 || reg > 31)
984     {
985       *errmsg = "invalid register number";
986       return 0;
987     }
988   xyzw = _parse_sdest (&str, errmsg);
989   if (*errmsg)
990     return 0;
991   *pstr = str;
992   return reg | (xyzw << 5);
993 }
994
995 static void
996 print_ffstreg (info, insn, value)
997      disassemble_info *info;
998      TXVU_INSN *insn;
999      long value;
1000 {
1001   (*info->fprintf_func) (info->stream, "vf%02ld", value & TXVU_MASK_REG);
1002   print_sdest (info, insn, (value >> 5) & 3);
1003 }
1004
1005 static void
1006 insert_ffstreg (insn, operand, mods, value, errmsg)
1007      TXVU_INSN *insn;
1008      const struct txvu_operand *operand;
1009      int mods;
1010      long value;
1011      const char **errmsg;
1012 {
1013   if (operand->shift == TXVU_SHIFT_SREG)
1014     *insn |= VLFSF (value >> 5) | VS (value);
1015   else
1016     *insn |= VLFTF (value >> 5) | VT (value);
1017 }
1018
1019 static long
1020 extract_ffstreg (insn, operand, mods, pinvalid)
1021      TXVU_INSN *insn;
1022      const struct txvu_operand *operand;
1023      int mods;
1024      int *pinvalid;
1025 {
1026   if (operand->shift == TXVU_SHIFT_SREG)
1027     return (((*insn & VLFSF (~0)) >> 21) << 5) | VS (*insn);
1028   else
1029     return (((*insn & VLFTF (~0)) >> 21) << 5) | VT (*insn);
1030 }
1031 \f
1032 /* F register.  */
1033
1034 static long
1035 parse_freg (pstr, errmsg)
1036      char **pstr;
1037      const char **errmsg;
1038 {
1039   char *str = *pstr;
1040   char *start;
1041   long reg;
1042
1043   if (tolower (str[0]) != 'v'
1044       || tolower (str[1]) != 'f')
1045     {
1046       *errmsg = "unknown register";
1047       return 0;
1048     }
1049
1050   /* FIXME: quick hack until the framework works.  */
1051   start = str = str + 2;
1052   while (*str && isdigit (*str))
1053     ++str;
1054   reg = atoi (start);
1055   if (reg < 0 || reg > 31)
1056     {
1057       *errmsg = "invalid register number";
1058       return 0;
1059     }
1060   *pstr = str;
1061   return reg;
1062 }
1063
1064 static void
1065 print_freg (info, insn, value)
1066      disassemble_info *info;
1067      TXVU_INSN *insn;
1068      long value;
1069 {
1070   (*info->fprintf_func) (info->stream, "vf%02ld", value);
1071 }
1072 \f
1073 /* I register.  */
1074
1075 static long
1076 parse_ireg (pstr, errmsg)
1077      char **pstr;
1078      const char **errmsg;
1079 {
1080   char *str = *pstr;
1081   char *start;
1082   long reg;
1083
1084   if (tolower (str[0]) != 'v'
1085       || tolower (str[1]) != 'i')
1086     {
1087       *errmsg = "unknown register";
1088       return 0;
1089     }
1090
1091   /* FIXME: quick hack until the framework works.  */
1092   start = str = str + 2;
1093   while (*str && isdigit (*str))
1094     ++str;
1095   reg = atoi (start);
1096   if (reg < 0 || reg > 31)
1097     {
1098       *errmsg = "invalid register number";
1099       return 0;
1100     }
1101   *pstr = str;
1102   return reg;
1103 }
1104
1105 static void
1106 print_ireg (info, insn, value)
1107      disassemble_info *info;
1108      TXVU_INSN *insn;
1109      long value;
1110 {
1111   (*info->fprintf_func) (info->stream, "vi%02ld", value);
1112 }
1113 \f
1114 /* VI01 register.  */
1115
1116 static long
1117 parse_vi01 (pstr, errmsg)
1118      char **pstr;
1119      const char **errmsg;
1120 {
1121   char *str = *pstr;
1122   char *start;
1123   long reg;
1124
1125   if (tolower (str[0]) != 'v'
1126       || tolower (str[1]) != 'i')
1127     {
1128       *errmsg = "unknown register";
1129       return 0;
1130     }
1131
1132   /* FIXME: quick hack until the framework works.  */
1133   start = str = str + 2;
1134   while (*str && isdigit (*str))
1135     ++str;
1136   reg = atoi (start);
1137   if (reg != 1)
1138     {
1139       *errmsg = "vi01 required here";
1140       return 0;
1141     }
1142   *pstr = str;
1143   return reg;
1144 }
1145
1146 static void
1147 print_vi01 (info, insn, value)
1148      disassemble_info *info;
1149      TXVU_INSN *insn;
1150      long value;
1151 {
1152   (*info->fprintf_func) (info->stream, "vi01");
1153 }
1154 \f
1155 /* Lower instruction 12 bit unsigned immediate.  */
1156
1157 static void
1158 insert_luimm12 (insn, operand, mods, value, errmsg)
1159      TXVU_INSN *insn;
1160      const struct txvu_operand *operand;
1161      int mods;
1162      long value;
1163      const char **errmsg;
1164 {
1165   *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | VLIMM11 (value);
1166 }
1167
1168 static long
1169 extract_luimm12 (insn, operand, mods, pinvalid)
1170      TXVU_INSN *insn;
1171      const struct txvu_operand *operand;
1172      int mods;
1173      int *pinvalid;
1174 {
1175   return (((*insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (*insn);
1176 }
1177
1178 /* Lower instruction 12 bit unsigned immediate, upper 6 bits.  */
1179
1180 static void
1181 insert_luimm12up6 (insn, operand, mods, value, errmsg)
1182      TXVU_INSN *insn;
1183      const struct txvu_operand *operand;
1184      int mods;
1185      long value;
1186      const char **errmsg;
1187 {
1188   *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | (value & 0x7c0);
1189 }
1190 \f
1191 /* Lower instruction 15 bit unsigned immediate.  */
1192
1193 static void
1194 insert_luimm15 (insn, operand, mods, value, errmsg)
1195      TXVU_INSN *insn;
1196      const struct txvu_operand *operand;
1197      int mods;
1198      long value;
1199      const char **errmsg;
1200 {
1201   *insn |= VLUIMM15TOP (value >> 11) | VLIMM11 (value);
1202 }
1203
1204 static long
1205 extract_luimm15 (insn, operand, mods, pinvalid)
1206      TXVU_INSN *insn;
1207      const struct txvu_operand *operand;
1208      int mods;
1209      int *pinvalid;
1210 {
1211   return (((*insn & MLUIMM15TOP) >> 21) << 11) | VLIMM11 (*insn);
1212 }
1213 \f
1214 /* PKE support.  */
1215
1216 PARSE_FN (pke_ibit);
1217 PRINT_FN (pke_ibit);
1218
1219 PARSE_FN (pke_mode);
1220 PRINT_FN (pke_mode);
1221
1222 PARSE_FN (pke_ability);
1223 PRINT_FN (pke_ability);
1224
1225 PARSE_FN (pke_mpgaddr);
1226
1227 PARSE_FN (pke_varlendata);
1228
1229 PARSE_FN (pke_imrbits);
1230 PRINT_FN (pke_imrbits);
1231
1232 PARSE_FN (pke_unpacktype);
1233 PRINT_FN (pke_unpacktype);
1234
1235 PARSE_FN (pke_unpackaddr);
1236
1237 const struct txvu_operand pke_operands[] =
1238 {
1239   /* place holder (??? not sure if needed) */
1240 #define PKE_UNUSED 128
1241   { 0 },
1242
1243   /* The I bit.  */
1244 #define PKE_IBIT (PKE_UNUSED + 1)
1245   { 1, 31, TXVU_OPERAND_SUFFIX, parse_pke_ibit, 0, 0, print_pke_ibit },
1246
1247   /* An 8 bit unsigned immediate, stored in upper 8 bits of immed field.  */
1248 #define PKE_UIMM8UP (PKE_IBIT + 1)
1249   { 8, 8, 0, 0, 0, 0, 0 },
1250
1251   /* An 8 bit unsigned immediate, stored in lower 8 bits of immed field.  */
1252 #define PKE_UIMM8LO (PKE_UIMM8UP + 1)
1253   { 8, 0, 0, 0, 0, 0, 0 },
1254
1255   /* An 16 bit unsigned immediate, stored in lower 8 bits of immed field.  */
1256 #define PKE_UIMM16 (PKE_UIMM8LO + 1)
1257   { 16, 0, 0, 0, 0, 0, 0 },
1258
1259   /* The mode operand of `stmod'.  */
1260 #define PKE_MODE (PKE_UIMM16 + 1)
1261   { 2, 0, 0, parse_pke_mode, 0, 0, print_pke_mode },
1262
1263   /* The ability operand of `mskpath3'.  */
1264 #define PKE_ABILITY (PKE_MODE + 1)
1265   { 1, 15, 0, parse_pke_ability, 0, 0, print_pke_ability },
1266
1267   /* A VU address.  */
1268 #define PKE_VUADDR (PKE_ABILITY + 1)
1269   { 16, 0, 0, 0, 0, 0, 0 },
1270
1271   /* A 32 bit immediate, appearing in 2nd,3rd,4th,5th words.  */
1272 #define PKE_UIMM32 (PKE_VUADDR + 1)
1273   { 32, 0, 0, 0, 0, 0, 0 },
1274
1275   /* VU address used by mpg insn.  */
1276 #define PKE_MPGADDR (PKE_UIMM32 + 1)
1277   { 16, 0, TXVU_OPERAND_ADDRESS, parse_pke_mpgaddr, 0, 0, 0 },
1278
1279   /* A variable length data specifier.
1280      Any of: file name, number, or '*'.  */
1281 #define PKE_VARLENDATA (PKE_MPGADDR + 1)
1282   { 0, 0, 0, parse_pke_varlendata, 0, 0, 0 },
1283
1284   /* The IMR bits of the unpack insn.  */
1285 #define PKE_IMRBITS (PKE_VARLENDATA + 1)
1286   { 0, 0, 0, parse_pke_imrbits, 0, 0, print_pke_imrbits },
1287
1288   /* The type of the unpack insn.  */
1289 #define PKE_UNPACKTYPE (PKE_IMRBITS + 1)
1290   { 4, 24, 0, parse_pke_unpacktype, 0, 0, print_pke_unpacktype },
1291
1292   /* VU address used by unpack insn.  */
1293 #define PKE_UNPACKADDR (PKE_UIMM32 + 1)
1294   { 16, 0, TXVU_OPERAND_ADDRESS, parse_pke_unpackaddr, 0, 0, 0 },
1295
1296 /* end of list place holder */
1297   { 0 }
1298 };
1299
1300 /* Field mask values.  */
1301 #define MPKECMD 0x7f000000
1302 #define MPKEUNPACK 0x60000000
1303
1304 /* Field values.  */
1305 #define VPKECMD(x) V ((x), 7, 24)
1306 #define VPKEUNPACK V (0x60, 8, 24)
1307
1308 struct txvu_opcode pke_opcodes[] =
1309 {
1310   { "pkenop", { PKE_IBIT }, 0x7fffffff, 0 },
1311   { "stcycle", { PKE_IBIT, SP, PKE_UIMM8UP, C, PKE_UIMM8LO }, MPKECMD, VPKECMD (1) },
1312   { "offset", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (2) },
1313   { "base", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (3) },
1314   { "itop", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (4) },
1315   { "stmod", { PKE_IBIT, SP, PKE_MODE }, MPKECMD + V (~0, 14, 2), VPKECMD (5) },
1316   { "mskpath3", { PKE_IBIT, SP, PKE_ABILITY }, MPKECMD + V (~0, 15, 0), VPKECMD (6) },
1317   { "pkemark", { PKE_IBIT, SP, PKE_UIMM16 }, MPKECMD, VPKECMD (7) },
1318   { "flushe", { PKE_IBIT }, MPKECMD, VPKECMD (16) },
1319   { "flush", { PKE_IBIT }, MPKECMD, VPKECMD (17) },
1320   { "flusha", { PKE_IBIT }, MPKECMD, VPKECMD (19) },
1321   { "pkemscal", { PKE_IBIT, SP, PKE_VUADDR }, MPKECMD, VPKECMD (20) },
1322   { "pkemscnt", { PKE_IBIT }, MPKECMD, VPKECMD (23) },
1323   { "pkemscalf", { PKE_IBIT, SP, PKE_VUADDR }, MPKECMD, VPKECMD (21) },
1324
1325   /* 2 word instructions */
1326   { "stmask", { PKE_IBIT, SP, PKE_UIMM32 }, MPKECMD, VPKECMD (32), PKE_OPCODE_LEN2 },
1327
1328   /* 5 word instructions */
1329   { "strow", { PKE_IBIT, SP, PKE_UIMM32, PKE_UIMM32, PKE_UIMM32, PKE_UIMM32 }, MPKECMD, VPKECMD (48), PKE_OPCODE_LEN5 },
1330   { "stcol", { PKE_IBIT, SP, PKE_UIMM32, PKE_UIMM32, PKE_UIMM32, PKE_UIMM32 }, MPKECMD, VPKECMD (49), PKE_OPCODE_LEN5 },
1331
1332   /* variable length instructions */
1333   { "mpg", { PKE_IBIT, SP, PKE_MPGADDR, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x4a), PKE_OPCODE_LENVAR + PKE_OPCODE_MPG },
1334   { "direct", { PKE_IBIT, SP, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x50), PKE_OPCODE_LENVAR + PKE_OPCODE_DIRECT },
1335   { "directhl", { PKE_IBIT, SP, PKE_VARLENDATA }, MPKECMD, VPKECMD (0x51), PKE_OPCODE_LENVAR + PKE_OPCODE_DIRECT },
1336   { "unpack", { PKE_IMRBITS, SP, PKE_UNPACKTYPE, C, PKE_UNPACKADDR, C, PKE_VARLENDATA }, MPKEUNPACK, VPKEUNPACK, PKE_OPCODE_LENVAR + PKE_OPCODE_UNPACK },
1337 };
1338 const int pke_opcodes_count = sizeof (pke_opcodes) / sizeof (pke_opcodes[0]);
1339 \f
1340 /* PKE parse,insert,extract,print helper fns.  */
1341
1342 static long
1343 parse_pke_ibit (pstr, errmsg)
1344      char **pstr;
1345      const char **errmsg;
1346 {
1347 }
1348
1349 static void
1350 print_pke_ibit (info, insn, value)
1351      disassemble_info *info;
1352      TXVU_INSN *insn;
1353      long value;
1354 {
1355   (*info->fprintf_func) (info->stream, "???");
1356 }
1357
1358 static long
1359 parse_pke_mode (pstr, errmsg)
1360      char **pstr;
1361      const char **errmsg;
1362 {
1363 }
1364
1365 static void
1366 print_pke_mode (info, insn, value)
1367      disassemble_info *info;
1368      TXVU_INSN *insn;
1369      long value;
1370 {
1371   (*info->fprintf_func) (info->stream, "???");
1372 }
1373
1374 static long
1375 parse_pke_ability (pstr, errmsg)
1376      char **pstr;
1377      const char **errmsg;
1378 {
1379 }
1380
1381 static void
1382 print_pke_ability (info, insn, value)
1383      disassemble_info *info;
1384      TXVU_INSN *insn;
1385      long value;
1386 {
1387   (*info->fprintf_func) (info->stream, "???");
1388 }
1389
1390 static long
1391 parse_pke_mpgaddr (pstr, errmsg)
1392      char **pstr;
1393      const char **errmsg;
1394 {
1395 }
1396
1397 static long
1398 parse_pke_varlendata (pstr, errmsg)
1399      char **pstr;
1400      const char **errmsg;
1401 {
1402   /* The result here is either the length specified,
1403      or PKE_VARLENDATA_FILE or PKE_VARLENDATA_UNKNOWN.  */
1404 }
1405
1406 static long
1407 parse_pke_imrbits (pstr, errmsg)
1408      char **pstr;
1409      const char **errmsg;
1410 {
1411 }
1412
1413 static void
1414 print_pke_imrbits (info, insn, value)
1415      disassemble_info *info;
1416      TXVU_INSN *insn;
1417      long value;
1418 {
1419   (*info->fprintf_func) (info->stream, "???");
1420 }
1421
1422 static long
1423 parse_pke_unpacktype (pstr, errmsg)
1424      char **pstr;
1425      const char **errmsg;
1426 {
1427 }
1428
1429 static void
1430 print_pke_unpacktype (info, insn, value)
1431      disassemble_info *info;
1432      TXVU_INSN *insn;
1433      long value;
1434 {
1435   (*info->fprintf_func) (info->stream, "???");
1436 }
1437
1438 static long
1439 parse_pke_unpackaddr (pstr, errmsg)
1440      char **pstr;
1441      const char **errmsg;
1442 {
1443 }
1444 \f
1445 /* DMA support.  */
1446
1447 PARSE_FN (dma_flags);
1448 INSERT_FN (dma_flags);
1449 EXTRACT_FN (dma_flags);
1450 PRINT_FN (dma_flags);
1451
1452 PARSE_FN (dma_data);
1453 INSERT_FN (dma_data);
1454 EXTRACT_FN (dma_data);
1455 PRINT_FN (dma_data);
1456
1457 PARSE_FN (dma_next);
1458 INSERT_FN (dma_next);
1459 EXTRACT_FN (dma_next);
1460 PRINT_FN (dma_next);
1461
1462 const struct txvu_operand dma_operands[] =
1463 {
1464   /* place holder (??? not sure if needed) */
1465 #define DMA_UNUSED 128
1466   { 0 },
1467
1468   /* dma tag flag bits */
1469 #define DMA_FLAGS (DMA_UNUSED + 1)
1470   { 0, 0, TXVU_OPERAND_SUFFIX,
1471       parse_dma_flags, insert_dma_flags, extract_dma_flags, print_dma_flags },
1472
1473   /* dma tag flag bits */
1474 #define DMA_DATA (DMA_FLAGS + 1)
1475   { 0, 0, 0,
1476       parse_dma_data, insert_dma_data, extract_dma_data, print_dma_data },
1477
1478   /* dma tag flag bits */
1479 #define DMA_NEXT (DMA_DATA + 1)
1480   { 0, 0, 0,
1481       parse_dma_next, insert_dma_next, extract_dma_next, print_dma_next },
1482
1483 /* end of list place holder */
1484   { 0 }
1485 };
1486
1487 struct txvu_opcode dma_opcodes[] =
1488 {
1489   /* ??? Some of these may take optional arguments.
1490      The way to handle that is to have multiple table entries, those with and
1491      those without the optional arguments.  */
1492   { "dmacnt", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 1 },
1493   { "dmanext", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 2 },
1494   { "dmaref", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 3 },
1495   { "dmarefs", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 4 },
1496   { "dmacall", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 5 },
1497   { "dmaret", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 6 },
1498   { "dmaend", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 7 }
1499 };
1500 const int dma_opcodes_count = sizeof (dma_opcodes) / sizeof (dma_opcodes[0]);
1501 \f
1502 /* DMA parse,insert,extract,print helper fns.  */
1503
1504 static long
1505 parse_dma_flags (pstr, errmsg)
1506      char **pstr;
1507      const char **errmsg;
1508 {
1509   char *str = *pstr;
1510   int flags = 0;
1511
1512   if (*str != '[')
1513     return 0;
1514
1515   for (str = str + 1; *str != ']'; ++str)
1516     {
1517       switch (tolower (*str))
1518         {
1519         case '0' : flags |= DMA_FLAG_PCE0; break;
1520         case '1' : flags |= DMA_FLAG_PCE1; break;
1521         case 'i' : flags |= DMA_FLAG_INT; break;
1522         case 's' : flags |= DMA_FLAG_SPR; break;
1523         default : *errmsg = "unknown dma flag"; return 0;
1524         }
1525     }
1526
1527   *pstr = str + 1;
1528   return flags;
1529 }
1530
1531 static void
1532 insert_dma_flags (insn, operand, mods, value, errmsg)
1533      TXVU_INSN *insn;
1534      const struct txvu_operand *operand;
1535      int mods;
1536      long value;
1537      const char **errmsg;
1538 {
1539 }
1540
1541 static long
1542 extract_dma_flags (insn, operand, mods, pinvalid)
1543      TXVU_INSN *insn;
1544      const struct txvu_operand *operand;
1545      int mods;
1546      int *pinvalid;
1547 {
1548   return 0;
1549 }
1550
1551 static void
1552 print_dma_flags (info, insn, value)
1553      disassemble_info *info;
1554      TXVU_INSN *insn;
1555      long value;
1556 {
1557   if (value)
1558     {
1559       (*info->fprintf_func) (info->stream, "[");
1560       if (value & DMA_FLAG_PCE0)
1561         (*info->fprintf_func) (info->stream, "0");
1562       if (value & DMA_FLAG_PCE1)
1563         (*info->fprintf_func) (info->stream, "1");
1564       if (value & DMA_FLAG_INT)
1565         (*info->fprintf_func) (info->stream, "i");
1566       if (value & DMA_FLAG_SPR)
1567         (*info->fprintf_func) (info->stream, "s");
1568       (*info->fprintf_func) (info->stream, "]");
1569     }
1570 }
1571
1572 /* Parse a DMA data spec which can be either of '*' or a quad word count.  */
1573
1574 static long
1575 parse_dma_data (pstr, errmsg)
1576      char **pstr;
1577      const char **errmsg;
1578 {
1579   char *str = *pstr;
1580   long count;
1581
1582   if (*str == '*')
1583     {
1584       ++*pstr;
1585       /* -1 is a special marker to caller to tell it the count is to be
1586          computed from the data.  */
1587       return -1;
1588     }
1589
1590   if (isdigit (*str))
1591     {
1592       char *start = str;
1593       while (*str && *str != ',')
1594         ++str;
1595       if (*str != ',')
1596         {
1597           *errmsg = "invalid dma count";
1598           return 0;
1599         }
1600       count = atoi (start);
1601       *pstr = str;
1602       return count;
1603     }
1604
1605   *errmsg = "invalid dma count";
1606   return 0;
1607 }
1608
1609 static void
1610 insert_dma_data (insn, operand, mods, value, errmsg)
1611      TXVU_INSN *insn;
1612      const struct txvu_operand *operand;
1613      int mods;
1614      long value;
1615      const char **errmsg;
1616 {
1617 }
1618
1619 static long
1620 extract_dma_data (insn, operand, mods, pinvalid)
1621      TXVU_INSN *insn;
1622      const struct txvu_operand *operand;
1623      int mods;
1624      int *pinvalid;
1625 {
1626   return 0;
1627 }
1628
1629 static void
1630 print_dma_data (info, insn, value)
1631      disassemble_info *info;
1632      TXVU_INSN *insn;
1633      long value;
1634 {
1635   (*info->fprintf_func) (info->stream, "???");
1636 }
1637
1638 static long
1639 parse_dma_next (pstr, errmsg)
1640      char **pstr;
1641      const char **errmsg;
1642 {
1643   char *start = *pstr;
1644   char *end = scan_symbol (start);
1645
1646   if (end == start)
1647     {
1648       *errmsg = "invalid dma next tag";
1649       return 0;
1650     }
1651   /* FIXME: unfinished */
1652   *pstr = end;
1653   return 0;
1654 }
1655
1656 static void
1657 insert_dma_next (insn, operand, mods, value, errmsg)
1658      TXVU_INSN *insn;
1659      const struct txvu_operand *operand;
1660      int mods;
1661      long value;
1662      const char **errmsg;
1663 {
1664 }
1665
1666 static long
1667 extract_dma_next (insn, operand, mods, pinvalid)
1668      TXVU_INSN *insn;
1669      const struct txvu_operand *operand;
1670      int mods;
1671      int *pinvalid;
1672 {
1673   return 0;
1674 }
1675
1676 static void
1677 print_dma_next (info, insn, value)
1678      disassemble_info *info;
1679      TXVU_INSN *insn;
1680      long value;
1681 {
1682   (*info->fprintf_func) (info->stream, "???");
1683 }
1684 \f
1685 /* GPUIF support.  */
1686
1687 PARSE_FN (gpuif_prim);
1688 INSERT_FN (gpuif_prim);
1689 EXTRACT_FN (gpuif_prim);
1690 PRINT_FN (gpuif_prim);
1691
1692 PARSE_FN (gpuif_regs);
1693 INSERT_FN (gpuif_regs);
1694 EXTRACT_FN (gpuif_regs);
1695 PRINT_FN (gpuif_regs);
1696
1697 PARSE_FN (gpuif_nloop);
1698 INSERT_FN (gpuif_nloop);
1699 EXTRACT_FN (gpuif_nloop);
1700 PRINT_FN (gpuif_nloop);
1701
1702 PARSE_FN (gpuif_eop);
1703 INSERT_FN (gpuif_eop);
1704 EXTRACT_FN (gpuif_eop);
1705 PRINT_FN (gpuif_eop);
1706
1707 const struct txvu_operand gpuif_operands[] =
1708 {
1709   /* place holder (??? not sure if needed) */
1710 #define GPUIF_UNUSED 128
1711   { 0 },
1712
1713   /* PRIM=foo operand */
1714 #define GPUIF_PRIM (GPUIF_UNUSED + 1)
1715   { 0, 0, 0, parse_gpuif_prim, insert_gpuif_prim, extract_gpuif_prim, print_gpuif_prim },
1716
1717   /* REGS=foo operand */
1718 #define GPUIF_REGS (GPUIF_PRIM + 1)
1719   { 0, 0, 0, parse_gpuif_regs, insert_gpuif_regs, extract_gpuif_regs, print_gpuif_regs },
1720
1721   /* NLOOP=foo operand */
1722 #define GPUIF_NLOOP (GPUIF_REGS + 1)
1723   { 0, 0, 0, parse_gpuif_nloop, insert_gpuif_nloop, extract_gpuif_nloop, print_gpuif_nloop },
1724
1725   /* EOP operand */
1726 #define GPUIF_EOP (GPUIF_NLOOP + 1)
1727   { 0, 0, 0, parse_gpuif_eop, insert_gpuif_eop, extract_gpuif_eop, print_gpuif_eop },
1728
1729 /* end of list place holder */
1730   { 0 }
1731 };
1732
1733 struct txvu_opcode gpuif_opcodes[] =
1734 {
1735   /* Some of these may take optional arguments.
1736      The way this is handled is to have multiple table entries, those with and
1737      those without the optional arguments.  */
1738
1739   { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
1740   { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
1741   { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
1742   { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
1743   { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
1744   { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
1745   { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS }, 0, 1 },
1746   { "gpuifpacked", { SP, GPUIF_REGS }, 0, 1 },
1747
1748   { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 2 },
1749   { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 2 },
1750   { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 2 },
1751   { "gpuifreglist", { SP, GPUIF_REGS }, 0, 2 },
1752
1753   { "gpuifimage", { SP, GPUIF_NLOOP }, 0, 3 },
1754   { "gpuifimage", { 0 }, 0, 3 },
1755 };
1756 const int gpuif_opcodes_count = sizeof (gpuif_opcodes) / sizeof (gpuif_opcodes[0]);
1757 \f
1758 /* GPUIF parse,insert,extract,print helper fns.  */
1759
1760 static long
1761 parse_gpuif_prim (pstr, errmsg)
1762      char **pstr;
1763      const char **errmsg;
1764 {
1765   char *str = *pstr;
1766   char *start;
1767   long prim;
1768
1769   if (strncasecmp (str, "prim=", 5) != 0)
1770     {
1771       *errmsg = "missing PRIM spec";
1772       return 0;
1773     }
1774   str += 5;
1775   for (start = str; isalnum (*str); ++str)
1776     continue;
1777   if (str == start)
1778     {
1779       *errmsg = "missing PRIM spec";
1780       return 0;
1781     }
1782   /* FIXME: Yes, atoi doesn't do error checking.  Later.  */
1783   prim = atoi (start);
1784   *pstr = str;
1785   return prim;
1786 }
1787
1788 static void
1789 insert_gpuif_prim (insn, operand, mods, value, errmsg)
1790      TXVU_INSN *insn;
1791      const struct txvu_operand *operand;
1792      int mods;
1793      long value;
1794      const char **errmsg;
1795 {
1796 }
1797
1798 static long
1799 extract_gpuif_prim (insn, operand, mods, pinvalid)
1800      TXVU_INSN *insn;
1801      const struct txvu_operand *operand;
1802      int mods;
1803      int *pinvalid;
1804 {
1805   return 0;
1806 }
1807
1808 static void
1809 print_gpuif_prim (info, insn, value)
1810      disassemble_info *info;
1811      TXVU_INSN *insn;
1812      long value;
1813 {
1814   (*info->fprintf_func) (info->stream, "???");
1815 }
1816
1817 static const keyword gpuif_regs[] = {
1818   { GPUIF_REG_PRIM,      "prim" },
1819   { GPUIF_REG_RGBAQ,     "rgbaq" },
1820   { GPUIF_REG_ST,        "st" },
1821   { GPUIF_REG_UV,        "uv" },
1822   { GPUIF_REG_XYZF2,     "xyzf2" },
1823   { GPUIF_REG_TEXCLUT_1, "texclut_1" },
1824   { GPUIF_REG_TEXCLUT_2, "texclut_2" },
1825   { GPUIF_REG_TEX0_1,    "tex0_1" },
1826   { GPUIF_REG_TEX0_2,    "tex0_2" },
1827   { GPUIF_REG_TEX1_1,    "tex1_1" },
1828   { GPUIF_REG_TEX1_2,    "tex1_2" },
1829   { GPUIF_REG_XYZF3,     "xyzf3" },
1830   { GPUIF_REG_PRMODE,    "prmode" },
1831   { GPUIF_REG_A_D,       "a_d" },
1832   { GPUIF_REG_NOP,       "nop" },
1833   { 0, 0 }
1834 };
1835
1836 /* Parse a REGS= spec.
1837    The result is ???.  */
1838
1839 static long
1840 parse_gpuif_regs (pstr, errmsg)
1841      char **pstr;
1842      const char **errmsg;
1843 {
1844   char *str = *pstr;
1845   char *start;
1846   char c;
1847   int reg;
1848
1849   if (strncasecmp (str, "regs=", 5) != 0)
1850     {
1851       *errmsg = "missing REGS spec";
1852       return 0;
1853     }
1854   str += 5;
1855   SKIP_BLANKS (str);
1856   if (*str != '{')
1857     {
1858       *errmsg = "missing '{' in REGS spec";
1859       return 0;
1860     }
1861   ++str;
1862
1863   while (*str && *str != '}')
1864     {
1865       /* Pick out the register name.  */
1866
1867       SKIP_BLANKS (str);
1868       start = str;
1869       str = scan_symbol (str);
1870       if (str == start)
1871         {
1872           *errmsg = "invalid REG";
1873           return 0;
1874         }
1875
1876       /* Look it up in the table.  */
1877
1878       c = *str;
1879       *str = 0;
1880       reg = lookup_keyword_value (gpuif_regs, start, 0);
1881       *str = c;
1882       if (reg == -1)
1883         {
1884           *errmsg = "invalid REG";
1885           return 0;
1886         }
1887
1888       /* FIXME: save `reg' away somewhere */
1889
1890       /* Prepare for the next one.  */
1891
1892       SKIP_BLANKS (str);
1893       if (*str == ',')
1894         ++str;
1895       else if (*str != '}')
1896         break;
1897     }
1898   if (*str != '}')
1899     {
1900       *errmsg = "missing '{' in REGS spec";
1901       return 0;
1902     }
1903
1904   *pstr = str + 1;
1905   return 0; /* FIXME */
1906 }
1907
1908 static void
1909 insert_gpuif_regs (insn, operand, mods, value, errmsg)
1910      TXVU_INSN *insn;
1911      const struct txvu_operand *operand;
1912      int mods;
1913      long value;
1914      const char **errmsg;
1915 {
1916 }
1917
1918 static long
1919 extract_gpuif_regs (insn, operand, mods, pinvalid)
1920      TXVU_INSN *insn;
1921      const struct txvu_operand *operand;
1922      int mods;
1923      int *pinvalid;
1924 {
1925   return 0;
1926 }
1927
1928 static void
1929 print_gpuif_regs (info, insn, value)
1930      disassemble_info *info;
1931      TXVU_INSN *insn;
1932      long value;
1933 {
1934   (*info->fprintf_func) (info->stream, "???");
1935 }
1936
1937 static long
1938 parse_gpuif_nloop (pstr, errmsg)
1939      char **pstr;
1940      const char **errmsg;
1941 {
1942   char *str = *pstr;
1943   char *start;
1944   char c;
1945   int nloop;
1946
1947   if (strncasecmp (str, "nloop=", 6) != 0)
1948     {
1949       *errmsg = "missing NLOOP spec";
1950       return 0;
1951     }
1952   str += 6;
1953   SKIP_BLANKS (str);
1954   start = str;
1955   str = scan_symbol (str);
1956   if (str == start)
1957     {
1958       *errmsg = "invalid NOOP spec";
1959       return 0;
1960     }
1961   /* FIXME: error checking */
1962   nloop = atoi (start);
1963   *pstr = str;
1964   return nloop;
1965 }
1966
1967 static void
1968 insert_gpuif_nloop (insn, operand, mods, value, errmsg)
1969      TXVU_INSN *insn;
1970      const struct txvu_operand *operand;
1971      int mods;
1972      long value;
1973      const char **errmsg;
1974 {
1975 }
1976
1977 static long
1978 extract_gpuif_nloop (insn, operand, mods, pinvalid)
1979      TXVU_INSN *insn;
1980      const struct txvu_operand *operand;
1981      int mods;
1982      int *pinvalid;
1983 {
1984   return 0;
1985 }
1986
1987 static void
1988 print_gpuif_nloop (info, insn, value)
1989      disassemble_info *info;
1990      TXVU_INSN *insn;
1991      long value;
1992 {
1993   (*info->fprintf_func) (info->stream, "???");
1994 }
1995
1996 static long
1997 parse_gpuif_eop (pstr, errmsg)
1998      char **pstr;
1999      const char **errmsg;
2000 {
2001   if (strncasecmp (*pstr, "eop", 3) == 0)
2002     {
2003       *pstr += 3;
2004       return 1;
2005     }
2006   *errmsg = "missing `EOP'";
2007   return 0;
2008 }
2009
2010 static void
2011 insert_gpuif_eop (insn, operand, mods, value, errmsg)
2012      TXVU_INSN *insn;
2013      const struct txvu_operand *operand;
2014      int mods;
2015      long value;
2016      const char **errmsg;
2017 {
2018 }
2019
2020 static long
2021 extract_gpuif_eop (insn, operand, mods, pinvalid)
2022      TXVU_INSN *insn;
2023      const struct txvu_operand *operand;
2024      int mods;
2025      int *pinvalid;
2026 {
2027   return 0;
2028 }
2029
2030 static void
2031 print_gpuif_eop (info, insn, value)
2032      disassemble_info *info;
2033      TXVU_INSN *insn;
2034      long value;
2035 {
2036   (*info->fprintf_func) (info->stream, "???");
2037 }
2038 \f
2039 /* Init fns.
2040    These are called before doing each of the respective activities.  */
2041
2042 /* Called by the assembler before parsing an instruction.  */
2043
2044 void
2045 txvu_opcode_init_parse ()
2046 {
2047   mnemonic_dest = -1;
2048   mnemonic_bc = -1;
2049 }
2050
2051 /* Called by the disassembler before printing an instruction.  */
2052
2053 void
2054 txvu_opcode_init_print ()
2055 {
2056   mnemonic_dest = -1;
2057   mnemonic_bc = -1;
2058 }
2059 \f
2060 /* Indexed by first letter of opcode.  Points to chain of opcodes with same
2061    first letter.  */
2062 /* ??? One can certainly use a better hash.  Later.  */
2063 static struct txvu_opcode *upper_opcode_map[26 + 1];
2064 static struct txvu_opcode *lower_opcode_map[26 + 1];
2065
2066 /* Indexed by insn code.  Points to chain of opcodes with same insn code.  */
2067 static struct txvu_opcode *upper_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
2068 static struct txvu_opcode *lower_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
2069 \f
2070 /* Initialize any tables that need it.
2071    Must be called once at start up (or when first needed).
2072
2073    FLAGS is currently unused but is intended to control initialization.  */
2074
2075 void
2076 txvu_opcode_init_tables (flags)
2077      int flags;
2078 {
2079   static int init_p = 0;
2080
2081   /* We may be intentionally called more than once (for example gdb will call
2082      us each time the user switches cpu).  These tables only need to be init'd
2083      once though.  */
2084   /* ??? We can remove the need for txvu_opcode_supported by taking it into
2085      account here, but I'm not sure I want to do that yet (if ever).  */
2086   if (!init_p)
2087     {
2088       int i,n;
2089
2090       /* Upper VU table.  */
2091
2092       memset (upper_opcode_map, 0, sizeof (upper_opcode_map));
2093       memset (upper_icode_map, 0, sizeof (upper_icode_map));
2094       /* Scan the table backwards so macros appear at the front.  */
2095       for (i = txvu_upper_opcodes_count - 1; i >= 0; --i)
2096         {
2097           int opcode_hash = TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes[i].mnemonic);
2098           int icode_hash = TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes[i].value);
2099
2100           txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash];
2101           upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i];
2102
2103           txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash];
2104           upper_icode_map[icode_hash] = &txvu_upper_opcodes[i];
2105         }
2106
2107       /* Lower VU table.  */
2108
2109       memset (lower_opcode_map, 0, sizeof (lower_opcode_map));
2110       memset (lower_icode_map, 0, sizeof (lower_icode_map));
2111       /* Scan the table backwards so macros appear at the front.  */
2112       for (i = txvu_lower_opcodes_count - 1; i >= 0; --i)
2113         {
2114           int opcode_hash = TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes[i].mnemonic);
2115           int icode_hash = TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes[i].value);
2116
2117           txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash];
2118           lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i];
2119
2120           txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash];
2121           lower_icode_map[icode_hash] = &txvu_lower_opcodes[i];
2122         }
2123
2124       /* FIXME: We just hash everything to the same value for the rest.
2125          Quick hack while other things are worked on.  */
2126
2127       /* PKE table.  */
2128
2129       for (i = pke_opcodes_count - 2; i >= 0; --i)
2130         {
2131           pke_opcodes[i].next_asm = & pke_opcodes[i+1];
2132           pke_opcodes[i].next_dis = & pke_opcodes[i+1];
2133         }
2134
2135       /* DMA table.  */
2136
2137       for (i = dma_opcodes_count - 2; i >= 0; --i)
2138         {
2139           dma_opcodes[i].next_asm = & dma_opcodes[i+1];
2140           dma_opcodes[i].next_dis = & dma_opcodes[i+1];
2141         }
2142
2143       /* GPUIF table.  */
2144
2145       for (i = gpuif_opcodes_count - 2; i >= 0; --i)
2146         {
2147           gpuif_opcodes[i].next_asm = & gpuif_opcodes[i+1];
2148           gpuif_opcodes[i].next_dis = & gpuif_opcodes[i+1];
2149         }
2150
2151       init_p = 1;
2152     }
2153 }
2154
2155 /* Return the first insn in the chain for assembling upper INSN.  */
2156
2157 const struct txvu_opcode *
2158 txvu_upper_opcode_lookup_asm (insn)
2159      const char *insn;
2160 {
2161   return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)];
2162 }
2163
2164 /* Return the first insn in the chain for disassembling upper INSN.  */
2165
2166 const struct txvu_opcode *
2167 txvu_upper_opcode_lookup_dis (insn)
2168      TXVU_INSN insn;
2169 {
2170   return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)];
2171 }
2172
2173 /* Return the first insn in the chain for assembling lower INSN.  */
2174
2175 const struct txvu_opcode *
2176 txvu_lower_opcode_lookup_asm (insn)
2177      const char *insn;
2178 {
2179   return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)];
2180 }
2181
2182 /* Return the first insn in the chain for disassembling lower INSN.  */
2183
2184 const struct txvu_opcode *
2185 txvu_lower_opcode_lookup_dis (insn)
2186      TXVU_INSN insn;
2187 {
2188   return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)];
2189 }
2190
2191 /* Return the first insn in the chain for assembling lower INSN.  */
2192
2193 const struct txvu_opcode *
2194 pke_opcode_lookup_asm (insn)
2195      const char *insn;
2196 {
2197   return &pke_opcodes[0];
2198 }
2199
2200 /* Return the first insn in the chain for disassembling lower INSN.  */
2201
2202 const struct txvu_opcode *
2203 pke_opcode_lookup_dis (insn)
2204      TXVU_INSN insn;
2205 {
2206   return &pke_opcodes[0];
2207 }
2208
2209 /* Return the first insn in the chain for assembling lower INSN.  */
2210
2211 const struct txvu_opcode *
2212 dma_opcode_lookup_asm (insn)
2213      const char *insn;
2214 {
2215   return &dma_opcodes[0];
2216 }
2217
2218 /* Return the first insn in the chain for disassembling lower INSN.  */
2219
2220 const struct txvu_opcode *
2221 dma_opcode_lookup_dis (insn)
2222      TXVU_INSN insn;
2223 {
2224   return &dma_opcodes[0];
2225 }
2226
2227 /* Return the first insn in the chain for assembling lower INSN.  */
2228
2229 const struct txvu_opcode *
2230 gpuif_opcode_lookup_asm (insn)
2231      const char *insn;
2232 {
2233   return &gpuif_opcodes[0];
2234 }
2235
2236 /* Return the first insn in the chain for disassembling lower INSN.  */
2237
2238 const struct txvu_opcode *
2239 gpuif_opcode_lookup_dis (insn)
2240      TXVU_INSN insn;
2241 {
2242   return &gpuif_opcodes[0];
2243 }
2244 \f
2245 /* Misc. utilities.  */
2246
2247 /* Scan a symbol and return a pointer to one past the end.  */
2248
2249 static char *
2250 scan_symbol (sym)
2251      char *sym;
2252 {
2253   while (*sym && issymchar (*sym))
2254     ++sym;
2255   return sym;
2256 }
2257
2258 /* Given a keyword, look up its value, or -1 if not found.  */
2259
2260 static int
2261 lookup_keyword_value (table, name, case_sensitive_p)
2262      const keyword *table;
2263      const char *name;
2264      int case_sensitive_p;
2265 {
2266   const keyword *p;
2267
2268   if (case_sensitive_p)
2269     {
2270       for (p = table; p->name; ++p)
2271         if (strcmp (name, p->name) == 0)
2272           return p->value;
2273     }
2274   else
2275     {
2276       for (p = table; p->name; ++p)
2277         if (strcasecmp (name, p->name) == 0)
2278           return p->value;
2279     }
2280
2281   return -1;
2282 }
2283
2284 /* Given a keyword's value, look up its name, or NULL if not found.  */
2285
2286 static const char *
2287 lookup_keyword_name (table, value)
2288      const keyword *table;
2289      int value;
2290 {
2291   const keyword *p;
2292
2293   for (p = table; p->name; ++p)
2294     if (value == p->value)
2295       return p->name;
2296
2297   return NULL;
2298 }