* config.guess: More accurate determination of HP processor types.
[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 "sysdep.h"
20 #include "dis-asm.h"
21 #include "opcode/txvu.h"
22
23 #ifndef NULL
24 #define NULL 0
25 #endif
26
27 #if defined (__STDC__) || defined (ALMOST_STDC)
28 #define XCONCAT2(a,b)   a##b
29 #else
30 #define XCONCAT2(a,b)   a/**/b
31 #endif
32 #define CONCAT2(a,b)    XCONCAT2(a,b)
33
34 typedef struct {
35   int value;
36   const char *name;
37 } keyword;
38
39 static int lookup_keyword_value PARAMS ((const keyword *, const char *, int));
40 static const char *lookup_keyword_name PARAMS ((const keyword *table, int));
41
42 static char *scan_symbol PARAMS ((char *));
43
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 == '_')
47
48 #define SKIP_BLANKS(var) while (isspace (*(var))) ++(var)
49
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.  */
53
54 #define PARSE_FN(fn) \
55 static long CONCAT2 (parse_,fn) \
56      PARAMS ((const txvu_opcode *, const txvu_operand *, int, char **, \
57               const char **));
58 #define INSERT_FN(fn) \
59 static void CONCAT2 (insert_,fn) \
60      PARAMS ((const txvu_opcode *, const txvu_operand *, int, TXVU_INSN *, \
61               long, const char **))
62 #define EXTRACT_FN(fn) \
63 static long CONCAT2 (extract_,fn) \
64      PARAMS ((const txvu_opcode *, const txvu_operand *, int, TXVU_INSN *, \
65               int *));
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));
70
71 PARSE_FN (dotdest);
72 INSERT_FN (dotdest);
73 EXTRACT_FN (dotdest);
74 PRINT_FN (dotdest);
75
76 PARSE_FN (dotdest1);
77 PARSE_FN (dest1);
78 PRINT_FN (dest1);
79
80 PARSE_FN (bc);
81 EXTRACT_FN (bc);
82 PRINT_FN (sdest);
83
84 PARSE_FN (vfreg);
85 PRINT_FN (vfreg);
86
87 PARSE_FN (bcftreg);
88 PRINT_FN (bcftreg);
89
90 PARSE_FN (accdest);
91 PRINT_FN (accdest);
92
93 INSERT_FN (xyz);
94
95 PARSE_FN (ireg);
96 PRINT_FN (ireg);
97
98 PARSE_FN (freg);
99 PRINT_FN (freg);
100
101 PARSE_FN (ffstreg);
102 INSERT_FN (ffstreg);
103 EXTRACT_FN (ffstreg);
104 PRINT_FN (ffstreg);
105
106 PARSE_FN (vi01);
107 PRINT_FN (vi01);
108
109 INSERT_FN (luimm12);
110 EXTRACT_FN (luimm12);
111
112 INSERT_FN (luimm12up6);
113
114 INSERT_FN (luimm15);
115 EXTRACT_FN (luimm15);
116
117 /* Various types of TXVU operands, including insn suffixes.
118
119    Fields are:
120
121    BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
122
123    Operand values are 128 + table index.  This allows ASCII chars to be
124    included in the syntax spec.  */
125
126 const txvu_operand txvu_operands[] =
127 {
128   /* place holder (??? not sure if needed) */
129 #define UNUSED 128
130   { 0 },
131
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.  */
135
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 },
142
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 },
146
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 },
150
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 },
154
155   /* Upper word operands.  */
156
157   /* broadcast */
158 #define UBC (VFDREG + 1)
159   { 2, 0, TXVU_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest },
160
161   /* ftreg in broadcast case */
162 #define UBCFTREG (UBC + 1)
163   { 5, TXVU_SHIFT_TREG, 0, parse_bcftreg, 0, 0, print_bcftreg },
164
165   /* accumulator dest */
166 #define UACCDEST (UBCFTREG + 1)
167   { 0, 0, 0, parse_accdest, 0, 0, print_accdest },
168
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 },
173
174   /* Lower word operands.  */
175
176   /* 5 bit signed immediate.  */
177 #define LIMM5 (UXYZ + 1)
178   { 5, 6, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
179
180   /* 11 bit signed immediate.  */
181 #define LIMM11 (LIMM5 + 1)
182   { 11, 0, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
183
184   /* 15 bit unsigned immediate.  */
185 #define LUIMM15 (LIMM11 + 1)
186   { 15, 0, 0, 0, insert_luimm15, extract_luimm15, 0 },
187
188   /* ID register.  */
189 #define LIDREG (LUIMM15 + 1)
190   { 5, 6, 0, parse_ireg, 0, 0, print_ireg },
191
192   /* IS register.  */
193 #define LISREG (LIDREG + 1)
194   { 5, 11, 0, parse_ireg, 0, 0, print_ireg },
195
196   /* IT register.  */
197 #define LITREG (LISREG + 1)
198   { 5, 16, 0, parse_ireg, 0, 0, print_ireg },
199
200   /* FS reg, with FSF field selector.  */
201 #define LFSFFSREG (LITREG + 1)
202   { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
203
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 },
207
208   /* FT reg, with FTF field selector.  */
209 #define LFTFFTREG (LFSREG + 1)
210   { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
211
212   /* VI01 register.  */
213 #define LVI01 (LFTFFTREG + 1)
214   { 0, 0, 0, parse_vi01, 0, 0, print_vi01 },
215
216   /* 24 bit unsigned immediate.  */
217 #define LUIMM24 (LVI01 + 1)
218   { 24, 0, 0, 0, 0, 0, 0 },
219
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 },
223
224   /* upper 6 bits of 12 bit unsigned immediate */
225 #define LUIMM12UP6 (LUIMM12 + 1)
226   { 12, 0, 0, 0, insert_luimm12up6, extract_luimm12, 0 },
227
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 },
231
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
236          vector case.  */
237       parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
238
239   /* Destination indicator, single letter only, no leading '.'.  */
240 #define LDEST1 (LDOTDEST1 + 1)
241   { 0, 0, 0, parse_dest1, 0, 0, print_dest1 },
242
243 /* end of list place holder */
244   { 0 }
245 };
246 \f
247 /* Macros to put a field's value into the right place.  */
248 /* ??? If assembler needs these, move to opcode/txvu.h.  */
249
250 /* value X, B bits, shift S */
251 #define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s))
252
253 /* Field value macros for both upper and lower instructions.
254    These shift a value into the right place in the instruction.  */
255
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)
262 /* DEST field.  */
263 #define VDEST(x) V ((x), 4, 21)
264
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.  */
267
268 #define MT VT (~0)
269 #define MS VS (~0)
270 #define MD VD (~0)
271 #define MDEST VDEST (~0)
272
273 /* Upper instruction Value macros.  */
274
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)
289
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)
297
298 /* A space, separates instruction name (mnemonic + mnemonic operands) from
299    operands.  */
300 #define SP ' '
301 /* Commas separate operands.  */
302 #define C ','
303 /* Special I,P,Q,R operands.  */
304 #define I 'i'
305 #define P 'p'
306 #define Q 'q'
307 #define R 'r'
308
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]
312
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 ']'.
316
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.
320
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.  */
324
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
327    we need to.  */
328
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.  */
332
333 struct txvu_opcode txvu_upper_opcodes[] =
334 {
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.  */
338
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) }
400 };
401 const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_upper_opcodes[0]);
402 \f
403 /* Lower instruction Value macros.  */
404
405 /* 6 bit opcode.  */
406 #define VLOP6(x) V ((x), 6, 0)
407 /* 7 bit opcode.  */
408 #define VLOP7(x) V ((x), 7, 25)
409 /* 11 bit opcode.  */
410 #define VLOP11(x) V ((x), 11, 0)
411 /* 11 bit immediate.  */
412 #define VLIMM11(x) V ((x), 11, 0)
413 /* FTF field.  */
414 #define VLFTF(x) V ((x), 2, 23)
415 /* FSF field.  */
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)
421
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
434
435 struct txvu_opcode txvu_lower_opcodes[] =
436 {
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) },
441
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) }
514 };
515 const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]);
516 \f
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;
521
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;
526 \f
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.]  */
530
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.  */
535
536 static long
537 u_parse_dest (pstr)
538      char **pstr;
539 {
540   long dest = 0;
541
542   while (**pstr)
543     {
544       switch (**pstr)
545         {
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;
551         }
552       ++*pstr;
553     }
554
555   return dest;
556 }
557
558 static long
559 parse_dotdest (opcode, operand, mods, pstr, errmsg)
560      const txvu_opcode *opcode;
561      const txvu_operand *operand;
562      int mods;
563      char **pstr;
564      const char **errmsg;
565 {
566   long dest;
567
568   if (**pstr != '.' && **pstr != '/')
569     {
570       *errmsg = "missing `.'";
571       return 0;
572     }
573
574   ++*pstr;
575   dest = u_parse_dest (pstr);
576   if (dest == 0 || isalnum (**pstr))
577     {
578       *errmsg = "invalid `dest'";
579       return 0;
580     }
581
582   return dest;
583 }
584
585 /* Parse a `dest' spec where only a single letter is allowed,
586    but the encoding handles all four.  */
587
588 static long
589 parse_dotdest1 (opcode, operand, mods, pstr, errmsg)
590      const txvu_opcode *opcode;
591      const txvu_operand *operand;
592      int mods;
593      char **pstr;
594      const char **errmsg;
595 {
596   char c;
597   long dest;
598
599   if (**pstr != '.' && **pstr != '/')
600     {
601       *errmsg = "missing `.'";
602       return 0;
603     }
604
605   ++*pstr;
606   switch (**pstr)
607     {
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;
613     }
614   ++*pstr;
615   c = tolower (**pstr);
616   if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
617     {
618       *errmsg = "only one of x,y,z,w can be specified";
619       return 0;
620     }
621   if (isalnum (**pstr))
622     {
623       *errmsg = "invalid `dest'";
624       return 0;
625     }
626
627   return dest;
628 }
629
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'.  */
633
634 static long
635 parse_dest1 (opcode, operand, mods, pstr, errmsg)
636      const txvu_opcode *opcode;
637      const txvu_operand *operand;
638      int mods;
639      char **pstr;
640      const char **errmsg;
641 {
642   char c;
643   long dest;
644
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)
650     {
651       *errmsg = "expecting one of x,y,z,w";
652       return 0;
653     }
654
655   if (dest != state_vu_mnemonic_dest)
656     {
657       *errmsg = "`dest' suffix does not match instruction `dest'";
658       return 0;
659     }
660
661   return dest;
662 }
663
664 static void
665 insert_dotdest (opcode, operand, mods, insn, value, errmsg)
666      const txvu_opcode *opcode;
667      const txvu_operand *operand;
668      int mods;
669      TXVU_INSN *insn;
670      long value;
671      const char **errmsg;
672 {
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;
676 }
677
678 static long
679 extract_dotdest (opcode, operand, mods, insn, pinvalid)
680      const txvu_opcode *opcode;
681      const txvu_operand *operand;
682      int mods;
683      TXVU_INSN *insn;
684      int *pinvalid;
685 {
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;
689 }
690
691 /* Utility to print a multiple dest spec.  */
692
693 static void
694 u_print_dest (info, insn, value)
695      disassemble_info *info;
696      TXVU_INSN *insn;
697      long value;
698 {
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");
707 }
708
709 static void
710 print_dotdest (opcode, operand, mods, insn, info, value)
711      const txvu_opcode *opcode;
712      const txvu_operand *operand;
713      int mods;
714      TXVU_INSN *insn;
715      disassemble_info *info;
716      long value;
717 {
718   (*info->fprintf_func) (info->stream, ".");
719   u_print_dest (info, insn, value);
720 }
721
722 static void
723 print_dest1 (opcode, operand, mods, insn, info, value)
724      const txvu_opcode *opcode;
725      const txvu_operand *operand;
726      int mods;
727      TXVU_INSN *insn;
728      disassemble_info *info;
729      long value;
730 {
731   u_print_dest (info, insn, state_vu_mnemonic_dest);
732 }
733
734 /* Utilities for single destination choice handling.  */
735
736 static long
737 u_parse_sdest (pstr, errmsg)
738      char **pstr;
739      const char **errmsg;
740 {
741   char c;
742   long dest = 0;
743
744   switch (**pstr)
745     {
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;
751     }
752   ++*pstr;
753   c = tolower (**pstr);
754   if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
755     {
756       *errmsg = "only one of x,y,z,w can be specified";
757       return 0;
758     }
759   if (isalnum (**pstr))
760     {
761       *errmsg = "invalid `dest'";
762       return 0;
763     }
764
765   return dest;
766 }
767
768 static void
769 print_sdest (opcode, operand, mods, insn, info, value)
770      const txvu_opcode *opcode;
771      const txvu_operand *operand;
772      int mods;
773      TXVU_INSN *insn;
774      disassemble_info *info;
775      long value;
776 {
777   char c;
778
779   switch (value)
780     {
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;
785     }
786
787   (*info->fprintf_func) (info->stream, "%c", c);
788 }
789
790 /* Broadcase field.  */
791
792 static long
793 parse_bc (opcode, operand, mods, pstr, errmsg)
794      const txvu_opcode *opcode;
795      const txvu_operand *operand;
796      int mods;
797      char **pstr;
798      const char **errmsg;
799 {
800   long value = u_parse_sdest (pstr, errmsg);
801
802   if (*errmsg)
803     return 0;
804   /* Save value for later verification in register parsing.  */
805   state_vu_mnemonic_bc = value;
806   return value;
807 }
808
809 /* During the extraction process, save the bc field for use in
810    printing the bc register.  */
811
812 static long
813 extract_bc (opcode, operand, mods, insn, pinvalid)
814      const txvu_opcode *opcode;
815      const txvu_operand *operand;
816      int mods;
817      TXVU_INSN *insn;
818      int *pinvalid;
819 {
820   state_vu_mnemonic_bc = *insn & 3;
821   return state_vu_mnemonic_bc;
822 }
823
824 static long
825 parse_vfreg (opcode, operand, mods, pstr, errmsg)
826      const txvu_opcode *opcode;
827      const txvu_operand *operand;
828      int mods;
829      char **pstr;
830      const char **errmsg;
831 {
832   char *str = *pstr;
833   char *start;
834   long reg;
835   int reg_dest;
836
837   if (tolower (str[0]) != 'v'
838       || tolower (str[1]) != 'f')
839     {
840       *errmsg = "unknown register";
841       return 0;
842     }
843
844   /* FIXME: quick hack until the framework works.  */
845   start = str = str + 2;
846   while (*str && isdigit (*str))
847     ++str;
848   reg = atoi (start);
849   if (reg < 0 || reg > 31)
850     {
851       *errmsg = "invalid register number";
852       return 0;
853     }
854   reg_dest = u_parse_dest (&str);
855   if (reg_dest == 0 || isalnum (*str))
856     {
857       *errmsg = "invalid `dest'";
858       return 0;
859     }
860   if (reg_dest != state_vu_mnemonic_dest)
861     {
862       *errmsg = "register `dest' does not match instruction `dest'";
863       return 0;
864     }
865   *pstr = str;
866   return reg;
867 }
868
869 static void
870 print_vfreg (opcode, operand, mods, insn, info, value)
871      const txvu_opcode *opcode;
872      const txvu_operand *operand;
873      int mods;
874      disassemble_info *info;
875      TXVU_INSN *insn;
876      long value;
877 {
878   (*info->fprintf_func) (info->stream, "vf%02ld", value);
879   u_print_dest (info, insn, state_vu_mnemonic_dest);
880 }
881
882 /* FT register in broadcast case.  */
883
884 static long
885 parse_bcftreg (opcode, operand, mods, pstr, errmsg)
886      const txvu_opcode *opcode;
887      const txvu_operand *operand;
888      int mods;
889      char **pstr;
890      const char **errmsg;
891 {
892   char *str = *pstr;
893   char *start;
894   long reg;
895   int reg_bc;
896
897   if (tolower (str[0]) != 'v'
898       || tolower (str[1]) != 'f')
899     {
900       *errmsg = "unknown register";
901       return 0;
902     }
903
904   /* FIXME: quick hack until the framework works.  */
905   start = str = str + 2;
906   while (*str && isdigit (*str))
907     ++str;
908   reg = atoi (start);
909   if (reg < 0 || reg > 31)
910     {
911       *errmsg = "invalid register number";
912       return 0;
913     }
914   reg_bc = u_parse_sdest (&str, errmsg);
915   if (*errmsg)
916     return 0;
917   if (reg_bc != state_vu_mnemonic_bc)
918     {
919       *errmsg = "register `bc' does not match instruction `bc'";
920       return 0;
921     }
922   *pstr = str;
923   return reg;
924 }
925
926 static void
927 print_bcftreg (opcode, operand, mods, insn, info, value)
928      const txvu_opcode *opcode;
929      const txvu_operand *operand;
930      int mods;
931      TXVU_INSN *insn;
932      disassemble_info *info;
933      long value;
934 {
935   (*info->fprintf_func) (info->stream, "vf%02ld", value);
936   print_sdest (opcode, operand, mods, insn, info, state_vu_mnemonic_bc);
937 }
938
939 /* ACC handling.  */
940
941 static long
942 parse_accdest (opcode, operand, mods, pstr, errmsg)
943      const txvu_opcode *opcode;
944      const txvu_operand *operand;
945      int mods;
946      char **pstr;
947      const char **errmsg;
948 {
949   char *str = *pstr;
950   long acc_dest = 0;
951
952   if (strncasecmp (str, "acc", 3) != 0)
953     {
954       *errmsg = "expecting `acc'";
955       return 0;
956     }
957   str += 3;
958   acc_dest = u_parse_dest (&str);
959   if (acc_dest == 0 || isalnum (*str))
960     {
961       *errmsg = "invalid `dest'";
962       return 0;
963     }
964   if (acc_dest != state_vu_mnemonic_dest)
965     {
966       *errmsg = "acc `dest' does not match instruction `dest'";
967       return 0;
968     }
969   *pstr = str;
970   /* Value isn't used, but we must return something.  */
971   return 0;
972 }
973
974 static void
975 print_accdest (opcode, operand, mods, insn, info, value)
976      const txvu_opcode *opcode;
977      const txvu_operand *operand;
978      int mods;
979      disassemble_info *info;
980      TXVU_INSN *insn;
981      long value;
982 {
983   (*info->fprintf_func) (info->stream, "acc");
984   u_print_dest (info, insn, state_vu_mnemonic_dest);
985 }
986
987 /* XYZ operand handling.
988    This simplifies the opmula,opmsub entries by keeping them equivalent to
989    the others.  */
990
991 static void
992 insert_xyz (opcode, operand, mods, insn, value, errmsg)
993      const txvu_opcode *opcode;
994      const txvu_operand *operand;
995      int mods;
996      TXVU_INSN *insn;
997      long value;
998      const char **errmsg;
999 {
1000   if (state_vu_mnemonic_dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
1001     *errmsg = "expecting `xyz' for `dest' value";
1002 }
1003
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.  */
1007
1008 static long
1009 parse_ffstreg (opcode, operand, mods, pstr, errmsg)
1010      const txvu_opcode *opcode;
1011      const txvu_operand *operand;
1012      int mods;
1013      char **pstr;
1014      const char **errmsg;
1015 {
1016   char *str = *pstr;
1017   char *start;
1018   int reg, xyzw;
1019
1020   if (tolower (str[0]) != 'v'
1021       || tolower (str[1]) != 'f')
1022     {
1023       *errmsg = "unknown register";
1024       return 0;
1025     }
1026
1027   /* FIXME: quick hack until the framework works.  */
1028   start = str = str + 2;
1029   while (*str && isdigit (*str))
1030     ++str;
1031   reg = atoi (start);
1032   if (reg < 0 || reg > 31)
1033     {
1034       *errmsg = "invalid register number";
1035       return 0;
1036     }
1037   xyzw = u_parse_sdest (&str, errmsg);
1038   if (*errmsg)
1039     return 0;
1040   *pstr = str;
1041   return reg | (xyzw << 5);
1042 }
1043
1044 static void
1045 print_ffstreg (opcode, operand, mods, insn, info, value)
1046      const txvu_opcode *opcode;
1047      const txvu_operand *operand;
1048      int mods;
1049      TXVU_INSN *insn;
1050      disassemble_info *info;
1051      long value;
1052 {
1053   (*info->fprintf_func) (info->stream, "vf%02ld", value & TXVU_MASK_REG);
1054   print_sdest (opcode, operand, mods, insn, info, (value >> 5) & 3);
1055 }
1056
1057 static void
1058 insert_ffstreg (opcode, operand, mods, insn, value, errmsg)
1059      const txvu_opcode *opcode;
1060      const txvu_operand *operand;
1061      int mods;
1062      TXVU_INSN *insn;
1063      long value;
1064      const char **errmsg;
1065 {
1066   if (operand->shift == TXVU_SHIFT_SREG)
1067     *insn |= VLFSF (value >> 5) | VS (value);
1068   else
1069     *insn |= VLFTF (value >> 5) | VT (value);
1070 }
1071
1072 static long
1073 extract_ffstreg (opcode, operand, mods, insn, pinvalid)
1074      const txvu_opcode *opcode;
1075      const txvu_operand *operand;
1076      int mods;
1077      TXVU_INSN *insn;
1078      int *pinvalid;
1079 {
1080   if (operand->shift == TXVU_SHIFT_SREG)
1081     return (((*insn & VLFSF (~0)) >> 21) << 5) | VS (*insn);
1082   else
1083     return (((*insn & VLFTF (~0)) >> 21) << 5) | VT (*insn);
1084 }
1085
1086 /* F register.  */
1087
1088 static long
1089 parse_freg (opcode, operand, mods, pstr, errmsg)
1090      const txvu_opcode *opcode;
1091      const txvu_operand *operand;
1092      int mods;
1093      char **pstr;
1094      const char **errmsg;
1095 {
1096   char *str = *pstr;
1097   char *start;
1098   long reg;
1099
1100   if (tolower (str[0]) != 'v'
1101       || tolower (str[1]) != 'f')
1102     {
1103       *errmsg = "unknown register";
1104       return 0;
1105     }
1106
1107   /* FIXME: quick hack until the framework works.  */
1108   start = str = str + 2;
1109   while (*str && isdigit (*str))
1110     ++str;
1111   reg = atoi (start);
1112   if (reg < 0 || reg > 31)
1113     {
1114       *errmsg = "invalid register number";
1115       return 0;
1116     }
1117   *pstr = str;
1118   return reg;
1119 }
1120
1121 static void
1122 print_freg (opcode, operand, mods, insn, info, value)
1123      const txvu_opcode *opcode;
1124      const txvu_operand *operand;
1125      int mods;
1126      TXVU_INSN *insn;
1127      disassemble_info *info;
1128      long value;
1129 {
1130   (*info->fprintf_func) (info->stream, "vf%02ld", value);
1131 }
1132
1133 /* I register.  */
1134
1135 static long
1136 parse_ireg (opcode, operand, mods, pstr, errmsg)
1137      const txvu_opcode *opcode;
1138      const txvu_operand *operand;
1139      int mods;
1140      char **pstr;
1141      const char **errmsg;
1142 {
1143   char *str = *pstr;
1144   char *start;
1145   long reg;
1146
1147   if (tolower (str[0]) != 'v'
1148       || tolower (str[1]) != 'i')
1149     {
1150       *errmsg = "unknown register";
1151       return 0;
1152     }
1153
1154   /* FIXME: quick hack until the framework works.  */
1155   start = str = str + 2;
1156   while (*str && isdigit (*str))
1157     ++str;
1158   reg = atoi (start);
1159   if (reg < 0 || reg > 31)
1160     {
1161       *errmsg = "invalid register number";
1162       return 0;
1163     }
1164   *pstr = str;
1165   return reg;
1166 }
1167
1168 static void
1169 print_ireg (opcode, operand, mods, insn, info, value)
1170      const txvu_opcode *opcode;
1171      const txvu_operand *operand;
1172      int mods;
1173      TXVU_INSN *insn;
1174      disassemble_info *info;
1175      long value;
1176 {
1177   (*info->fprintf_func) (info->stream, "vi%02ld", value);
1178 }
1179
1180 /* VI01 register.  */
1181
1182 static long
1183 parse_vi01 (opcode, operand, mods, pstr, errmsg)
1184      const txvu_opcode *opcode;
1185      const txvu_operand *operand;
1186      int mods;
1187      char **pstr;
1188      const char **errmsg;
1189 {
1190   char *str = *pstr;
1191   char *start;
1192   long reg;
1193
1194   if (tolower (str[0]) != 'v'
1195       || tolower (str[1]) != 'i')
1196     {
1197       *errmsg = "unknown register";
1198       return 0;
1199     }
1200
1201   /* FIXME: quick hack until the framework works.  */
1202   start = str = str + 2;
1203   while (*str && isdigit (*str))
1204     ++str;
1205   reg = atoi (start);
1206   if (reg != 1)
1207     {
1208       *errmsg = "vi01 required here";
1209       return 0;
1210     }
1211   *pstr = str;
1212   return reg;
1213 }
1214
1215 static void
1216 print_vi01 (opcode, operand, mods, insn, info, value)
1217      const txvu_opcode *opcode;
1218      const txvu_operand *operand;
1219      int mods;
1220      TXVU_INSN *insn;
1221      disassemble_info *info;
1222      long value;
1223 {
1224   (*info->fprintf_func) (info->stream, "vi01");
1225 }
1226
1227 /* Lower instruction 12 bit unsigned immediate.  */
1228
1229 static void
1230 insert_luimm12 (opcode, operand, mods, insn, value, errmsg)
1231      const txvu_opcode *opcode;
1232      const txvu_operand *operand;
1233      int mods;
1234      TXVU_INSN *insn;
1235      long value;
1236      const char **errmsg;
1237 {
1238   *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | VLIMM11 (value);
1239 }
1240
1241 static long
1242 extract_luimm12 (opcode, operand, mods, insn, pinvalid)
1243      const txvu_opcode *opcode;
1244      const txvu_operand *operand;
1245      int mods;
1246      TXVU_INSN *insn;
1247      int *pinvalid;
1248 {
1249   return (((*insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (*insn);
1250 }
1251
1252 /* Lower instruction 12 bit unsigned immediate, upper 6 bits.  */
1253
1254 static void
1255 insert_luimm12up6 (opcode, operand, mods, insn, value, errmsg)
1256      const txvu_opcode *opcode;
1257      const txvu_operand *operand;
1258      int mods;
1259      TXVU_INSN *insn;
1260      long value;
1261      const char **errmsg;
1262 {
1263   *insn |= VLUIMM12TOP ((value & (1 << 11)) != 0) | (value & 0x7c0);
1264 }
1265
1266 /* Lower instruction 15 bit unsigned immediate.  */
1267
1268 static void
1269 insert_luimm15 (opcode, operand, mods, insn, value, errmsg)
1270      const txvu_opcode *opcode;
1271      const txvu_operand *operand;
1272      int mods;
1273      TXVU_INSN *insn;
1274      long value;
1275      const char **errmsg;
1276 {
1277   *insn |= VLUIMM15TOP (value >> 11) | VLIMM11 (value);
1278 }
1279
1280 static long
1281 extract_luimm15 (opcode, operand, mods, insn, pinvalid)
1282      const txvu_opcode *opcode;
1283      const txvu_operand *operand;
1284      int mods;
1285      TXVU_INSN *insn;
1286      int *pinvalid;
1287 {
1288   return (((*insn & MLUIMM15TOP) >> 21) << 11) | VLIMM11 (*insn);
1289 }
1290 \f
1291 /* PKE support.  */
1292
1293 PARSE_FN (pke_ibit);
1294 PRINT_FN (pke_ibit);
1295
1296 PARSE_FN (pke_mode);
1297 PRINT_FN (pke_mode);
1298
1299 PARSE_FN (pke_ability);
1300 PRINT_FN (pke_ability);
1301
1302 PARSE_FN (pke_mpgaddr);
1303
1304 PARSE_FN (pke_varlendata);
1305
1306 PARSE_FN (pke_imrbits);
1307 PRINT_FN (pke_imrbits);
1308
1309 PARSE_FN (pke_unpacktype);
1310 PRINT_FN (pke_unpacktype);
1311
1312 PARSE_FN (pke_unpackaddr);
1313
1314 const txvu_operand pke_operands[] =
1315 {
1316   /* place holder (??? not sure if needed) */
1317 #define PKE_UNUSED 128
1318   { 0 },
1319
1320   /* The I bit.  */
1321 #define PKE_IBIT (PKE_UNUSED + 1)
1322   { 1, 31, TXVU_OPERAND_SUFFIX, parse_pke_ibit, 0, 0, print_pke_ibit },
1323
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 },
1327
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 },
1331
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 },
1335
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 },
1339
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 },
1343
1344   /* A VU address.  */
1345 #define PKE_VUADDR (PKE_ABILITY + 1)
1346   { 16, 0, 0, 0, 0, 0, 0 },
1347
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 },
1351
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 },
1355
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 },
1360
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 },
1364
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 },
1368
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 },
1372
1373   /* Fake operand processed at end of parsing an insn to set the length.  */
1374
1375 /* end of list place holder */
1376   { 0 }
1377 };
1378
1379 /* Field mask values.  */
1380 #define MPKECMD 0x7f000000
1381 #define MPKEUNPACK 0x60000000
1382
1383 /* Field values.  */
1384 #define VPKECMD(x) V ((x), 7, 24)
1385 #define VPKEUNPACK V (0x60, 8, 24)
1386
1387 struct txvu_opcode pke_opcodes[] =
1388 {
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) },
1403
1404   /* 2 word instructions */
1405   { "stmask", { PKE_IBIT, SP, PKE_UIMM32 }, MPKECMD, VPKECMD (32), PKE_OPCODE_LEN2 },
1406
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 },
1410
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 },
1416 };
1417 const int pke_opcodes_count = sizeof (pke_opcodes) / sizeof (pke_opcodes[0]);
1418 \f
1419 /* Non-zero if a variable length instruction was parsed.  */
1420 static int state_pke_varlen_p;
1421
1422 /* Length of parsed insn, in 32 bit words, or 0 if unknown.  */
1423 static int state_pke_len;
1424 \f
1425 /* PKE parse,insert,extract,print helper fns.  */
1426
1427 static long
1428 parse_pke_ibit (opcode, operand, mods, pstr, errmsg)
1429      const txvu_opcode *opcode;
1430      const txvu_operand *operand;
1431      int mods;
1432      char **pstr;
1433      const char **errmsg;
1434 {
1435   char *str = *pstr;
1436   int flags = 0;
1437
1438   if (*str != '[')
1439     return 0;
1440
1441   for (str = str + 1; *str != ']'; ++str)
1442     {
1443       switch (tolower (*str))
1444         {
1445         case 'i' : flags = 1; break;
1446         default : *errmsg = "unknown flag"; return 0;
1447         }
1448     }
1449
1450   *pstr = str + 1;
1451   return flags;
1452 }
1453
1454 static void
1455 print_pke_ibit (opcode, operand, mods, insn, info, value)
1456      const txvu_opcode *opcode;
1457      const txvu_operand *operand;
1458      int mods;
1459      TXVU_INSN *insn;
1460      disassemble_info *info;
1461      long value;
1462 {
1463   if (value)
1464     (*info->fprintf_func) (info->stream, "[i]");
1465 }
1466
1467 static const keyword stmod_modes[] = {
1468   { PKE_MODE_DIRECT, "direct" },
1469   { PKE_MODE_ADD,    "add" },
1470   { PKE_MODE_ADDROW, "addrow" },
1471   { 0, 0 }
1472 };
1473
1474 static long
1475 parse_pke_mode (opcode, operand, mods, pstr, errmsg)
1476      const txvu_opcode *opcode;
1477      const txvu_operand *operand;
1478      int mods;
1479      char **pstr;
1480      const char **errmsg;
1481 {
1482   int mode;
1483   char *str = *pstr;
1484   char *start;
1485   char c;
1486
1487   start = str;
1488   str = scan_symbol (str);
1489   c = *str;
1490   *str = 0;
1491   mode = lookup_keyword_value (stmod_modes, start, 0);
1492   *str = c;
1493   if (mode != -1)
1494     {
1495       *pstr = str;
1496       return mode;
1497     }
1498   *errmsg = "invalid mode";
1499   return 0;
1500 }
1501
1502 static void
1503 print_pke_mode (opcode, operand, mods, insn, info, value)
1504      const txvu_opcode *opcode;
1505      const txvu_operand *operand;
1506      int mods;
1507      disassemble_info *info;
1508      TXVU_INSN *insn;
1509      long value;
1510 {
1511   const char *name = lookup_keyword_name (stmod_modes, value);
1512
1513   if (name)
1514     (*info->fprintf_func) (info->stream, name);
1515   else
1516     (*info->fprintf_func) (info->stream, "???");
1517 }
1518
1519 static long
1520 parse_pke_ability (opcode, operand, mods, pstr, errmsg)
1521      const txvu_opcode *opcode;
1522      const txvu_operand *operand;
1523      int mods;
1524      char **pstr;
1525      const char **errmsg;
1526 {
1527   char *str = *pstr;
1528
1529   if (strncasecmp (str, "disable", 7) == 0)
1530     {
1531       *pstr += 7;
1532       return 0;
1533     }
1534   else if (strncasecmp (str, "enable", 6) == 0)
1535     {
1536       *pstr += 6;
1537       return 1;
1538     }
1539   *errmsg = "invalid ability";
1540   return 0;
1541 }
1542
1543 static void
1544 print_pke_ability (opcode, operand, mods, insn, info, value)
1545      const txvu_opcode *opcode;
1546      const txvu_operand *operand;
1547      int mods;
1548      TXVU_INSN *insn;
1549      disassemble_info *info;
1550      long value;
1551 {
1552   if (value)
1553     (*info->fprintf_func) (info->stream, "enable");
1554   else
1555     (*info->fprintf_func) (info->stream, "disable");
1556 }
1557
1558 static long
1559 parse_pke_mpgaddr (opcode, operand, mods, pstr, errmsg)
1560      const txvu_opcode *opcode;
1561      const txvu_operand *operand;
1562      int mods;
1563      char **pstr;
1564      const char **errmsg;
1565 {
1566   char *str = *pstr;
1567   char *start;
1568
1569   if (*str == '*')
1570     {
1571       ++*pstr;
1572       return 0; /* FIXME:indicate * somehow */
1573     }
1574
1575   start = str;
1576   str = strchr (str, ',');
1577   if (! str)
1578     {
1579       *errmsg = "invalid mpg address";
1580       return 0;
1581     }
1582
1583   /* FIXME: call back to expression() to parse address.  */
1584
1585   *pstr = str;
1586   return 0;
1587 }
1588
1589 /* The result here is either the length specified,
1590    or PKE_VARLENDATA_FILE or PKE_VARLENDATA_UNKNOWN.  */
1591
1592 static long
1593 parse_pke_varlendata (opcode, operand, mods, pstr, errmsg)
1594      const txvu_opcode *opcode;
1595      const txvu_operand *operand;
1596      int mods;
1597      char **pstr;
1598      const char **errmsg;
1599 {
1600   char *str = *pstr;
1601   char *start;
1602
1603   if (*str == '*')
1604     {
1605       ++*pstr;
1606       return 0; /* FIXME:indicate * somehow */
1607     }
1608
1609   start = str;
1610
1611   /* FIXME: call back to expression() to parse address,
1612      and pick out filename if such.  */
1613
1614   *pstr = str + strlen (str);
1615   return 0;
1616 }
1617
1618 static long
1619 parse_pke_imrbits (opcode, operand, mods, pstr, errmsg)
1620      const txvu_opcode *opcode;
1621      const txvu_operand *operand;
1622      int mods;
1623      char **pstr;
1624      const char **errmsg;
1625 {
1626   char *str = *pstr;
1627   int flags = 0;
1628
1629   if (*str != '[')
1630     return 0;
1631
1632   for (str = str + 1; *str != ']'; ++str)
1633     {
1634       switch (tolower (*str))
1635         {
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;
1640         }
1641     }
1642
1643   *pstr = str + 1;
1644   return flags;
1645 }
1646
1647 static void
1648 print_pke_imrbits (opcode, operand, mods, insn, info, value)
1649      const txvu_opcode *opcode;
1650      const txvu_operand *operand;
1651      int mods;
1652      TXVU_INSN *insn;
1653      disassemble_info *info;
1654      long value;
1655 {
1656   if (value)
1657     {
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, "]");
1666     }
1667 }
1668
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" },
1683   { 0, 0 }
1684 };
1685
1686 static long
1687 parse_pke_unpacktype (opcode, operand, mods, pstr, errmsg)
1688      const txvu_opcode *opcode;
1689      const txvu_operand *operand;
1690      int mods;
1691      char **pstr;
1692      const char **errmsg;
1693 {
1694   int type;
1695   char *str = *pstr;
1696   char *start;
1697   char c;
1698
1699   start = str;
1700   str = scan_symbol (str);
1701   c = *str;
1702   *str = 0;
1703   type = lookup_keyword_value (unpack_types, start, 0);
1704   *str = c;
1705   if (type != -1)
1706     {
1707       *pstr = str;
1708       return type;
1709     }
1710   *errmsg = "invalid unpack type";
1711   return 0;
1712 }
1713
1714 static void
1715 print_pke_unpacktype (opcode, operand, mods, insn, info, value)
1716      const txvu_opcode *opcode;
1717      const txvu_operand *operand;
1718      int mods;
1719      TXVU_INSN *insn;
1720      disassemble_info *info;
1721      long value;
1722 {
1723   const char *name = lookup_keyword_name (unpack_types, value);
1724
1725   if (name)
1726     (*info->fprintf_func) (info->stream, name);
1727   else
1728     (*info->fprintf_func) (info->stream, "???");
1729 }
1730
1731 static long
1732 parse_pke_unpackaddr (opcode, operand, mods, pstr, errmsg)
1733      const txvu_opcode *opcode;
1734      const txvu_operand *operand;
1735      int mods;
1736      char **pstr;
1737      const char **errmsg;
1738 {
1739 }
1740 \f
1741 /* External PKE supporting routines.  */
1742
1743 /* Return non-zero if the just parsed pke insn has variable length.  */
1744
1745 int
1746 pke_varlen_p ()
1747 {
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)
1751     abort ();
1752
1753   return state_pke_varlen_p;
1754 }
1755
1756 /* Return length, in 32 bit words, of just parsed pke insn,
1757    or 0 if unknown.  */
1758
1759 int
1760 pke_len ()
1761 {
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)
1765     abort ();
1766
1767   return state_pke_len;
1768 }
1769 \f
1770 /* DMA support.  */
1771
1772 PARSE_FN (dma_flags);
1773 INSERT_FN (dma_flags);
1774 EXTRACT_FN (dma_flags);
1775 PRINT_FN (dma_flags);
1776
1777 PARSE_FN (dma_data);
1778 INSERT_FN (dma_data);
1779 EXTRACT_FN (dma_data);
1780 PRINT_FN (dma_data);
1781
1782 PARSE_FN (dma_next);
1783 INSERT_FN (dma_next);
1784 EXTRACT_FN (dma_next);
1785 PRINT_FN (dma_next);
1786
1787 const txvu_operand dma_operands[] =
1788 {
1789     /* place holder (??? not sure if needed) */
1790 #define DMA_UNUSED 128
1791     { 0 },
1792
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 },
1797
1798     /* dma data spec */
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 },
1802
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},
1807
1808     /* dma next tag spec */
1809 #define DMA_ADDR (DMA_DATA2 + 1)
1810     { 0, 0, 0,
1811       parse_dma_addr, insert_dma_addr, extract_dma_addr, print_dma_addr},
1812
1813 /* end of list place holder */
1814   { 0 }
1815 };
1816
1817 struct txvu_opcode dma_opcodes[] =
1818 {
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}
1831 };
1832 const int dma_opcodes_count = sizeof (dma_opcodes) / sizeof (dma_opcodes[0]);
1833
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;
1837 \f
1838 /* DMA parse,insert,extract,print helper fns.  */
1839
1840 static long
1841 parse_dma_flags (opcode, operand, mods, pstr, errmsg)
1842      const txvu_opcode *opcode;
1843      const txvu_operand *operand;
1844      int mods;
1845      char **pstr;
1846      const char **errmsg;
1847 {
1848   char *str = *pstr;
1849   int flags = 0;
1850
1851   if (*str != '[')
1852     return 0;
1853
1854   for (str = str + 1; *str != ']'; ++str)
1855     {
1856       switch (tolower (*str))
1857         {
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;
1863         }
1864     }
1865
1866   *pstr = str + 1;
1867   return flags;
1868 }
1869
1870 static void
1871 insert_dma_flags (opcode, operand, mods, insn, value, errmsg)
1872      const txvu_opcode *opcode;
1873      const txvu_operand *operand;
1874      int mods;
1875      TXVU_INSN *insn;
1876      long value;
1877      const char **errmsg;
1878 {
1879 }
1880
1881 static long
1882 extract_dma_flags (opcode, operand, mods, insn, pinvalid)
1883      const txvu_opcode *opcode;
1884      const txvu_operand *operand;
1885      int mods;
1886      TXVU_INSN *insn;
1887      int *pinvalid;
1888 {
1889   return 0;
1890 }
1891
1892 static void
1893 print_dma_flags (opcode, operand, mods, insn, info, value)
1894      const txvu_opcode *opcode;
1895      const txvu_operand *operand;
1896      int mods;
1897      TXVU_INSN *insn;
1898      disassemble_info *info;
1899      long value;
1900 {
1901   if (value)
1902     {
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, "]");
1913     }
1914 }
1915
1916 static long
1917 parse_dma_data2( opcode, operand, mods, pstr, errmsg)
1918     const txvu_opcode *opcode;
1919     const txvu_operand *operand;
1920     int mods;
1921     char **pstr;
1922     const char **errmsg;
1923 {
1924     /*
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
1929         else
1930             compute from current addr and end symbol
1931         store value to count field?
1932     */
1933 }
1934
1935 static void
1936 insert_dma_data (opcode, operand, mods, insn, value, errmsg)
1937      const txvu_opcode *opcode;
1938      const txvu_operand *operand;
1939      int mods;
1940      TXVU_INSN *insn;
1941      long value;
1942      const char **errmsg;
1943 {
1944 }
1945
1946 static long
1947 extract_dma_data (opcode, operand, mods, insn, pinvalid)
1948      const txvu_opcode *opcode;
1949      const txvu_operand *operand;
1950      int mods;
1951      TXVU_INSN *insn;
1952      int *pinvalid;
1953 {
1954   return 0;
1955 }
1956
1957 static void
1958 print_dma_data (opcode, operand, mods, insn, info, value)
1959      const txvu_opcode *opcode;
1960      const txvu_operand *operand;
1961      int mods;
1962      TXVU_INSN *insn;
1963      disassemble_info *info;
1964      long value;
1965 {
1966   (*info->fprintf_func) (info->stream, "???");
1967 }
1968
1969 static long
1970 parse_dma_addr (opcode, operand, mods, pstr, errmsg)
1971     const txvu_opcode *opcode;
1972     const txvu_operand *operand;
1973     int mods;
1974     char **pstr;
1975     const char **errmsg;
1976 {
1977     char *start = *pstr;
1978     char *end = scan_symbol( start);
1979
1980     if( end == start )
1981     {
1982         *errmsg = "invalid dma next tag";
1983         return 0;
1984     }
1985
1986     /* FIXME: unfinished
1987     if txvu_dma_operand_count() > 0
1988         if dmaref || dmarefs
1989             this operand must be a symbol (vs an expression)
1990             lookup the symbol
1991             store the symbol's value in the addr field (relocs?)
1992             compute the end_symbol's name
1993             lookup the end_symbol
1994             if not found: error
1995             compute the length as _$<name>-<name>
1996         else
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
2001     else
2002         evaluate the operand as an expression
2003         store the value to the count field
2004     */
2005
2006     parse_dma_data2( opcode, operand, mods, pstr, errmsg);
2007
2008     *pstr = end;
2009     return 0;
2010 }
2011
2012 static void
2013 insert_dma_addr (opcode, operand, mods, insn, value, errmsg)
2014      const txvu_opcode *opcode;
2015      const txvu_operand *operand;
2016      int mods;
2017      TXVU_INSN *insn;
2018      long value;
2019      const char **errmsg;
2020 {
2021 }
2022
2023 static long
2024 extract_dma_addr (opcode, operand, mods, insn, pinvalid)
2025      const txvu_opcode *opcode;
2026      const txvu_operand *operand;
2027      int mods;
2028      TXVU_INSN *insn;
2029      int *pinvalid;
2030 {
2031   return 0;
2032 }
2033
2034 static void
2035 print_dma_addr (opcode, operand, mods, insn, info, value)
2036      const txvu_opcode *opcode;
2037      const txvu_operand *operand;
2038      int mods;
2039      TXVU_INSN *insn;
2040      disassemble_info *info;
2041      long value;
2042 {
2043   (*info->fprintf_func) (info->stream, "???");
2044 }
2045 \f
2046 /* GPUIF support.  */
2047
2048 PARSE_FN (gpuif_prim);
2049 INSERT_FN (gpuif_prim);
2050 EXTRACT_FN (gpuif_prim);
2051 PRINT_FN (gpuif_prim);
2052
2053 PARSE_FN (gpuif_regs);
2054 INSERT_FN (gpuif_regs);
2055 EXTRACT_FN (gpuif_regs);
2056 PRINT_FN (gpuif_regs);
2057
2058 PARSE_FN (gpuif_nloop);
2059 INSERT_FN (gpuif_nloop);
2060 EXTRACT_FN (gpuif_nloop);
2061 PRINT_FN (gpuif_nloop);
2062
2063 PARSE_FN (gpuif_eop);
2064 INSERT_FN (gpuif_eop);
2065 EXTRACT_FN (gpuif_eop);
2066 PRINT_FN (gpuif_eop);
2067
2068 const txvu_operand gpuif_operands[] =
2069 {
2070   /* place holder (??? not sure if needed) */
2071 #define GPUIF_UNUSED 128
2072   { 0 },
2073
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 },
2077
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 },
2081
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 },
2085
2086   /* EOP operand */
2087 #define GPUIF_EOP (GPUIF_NLOOP + 1)
2088   { 0, 0, 0, parse_gpuif_eop, insert_gpuif_eop, extract_gpuif_eop, print_gpuif_eop },
2089
2090 /* end of list place holder */
2091   { 0 }
2092 };
2093
2094 struct txvu_opcode gpuif_opcodes[] =
2095 {
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
2104      syntax string.  */
2105
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 },
2114
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 },
2119
2120   { "gpuifimage", { SP, GPUIF_NLOOP }, 0, 3 },
2121   { "gpuifimage", { 0 }, 0, 3 },
2122 };
2123 const int gpuif_opcodes_count = sizeof (gpuif_opcodes) / sizeof (gpuif_opcodes[0]);
2124 \f
2125 /* GPUIF parse,insert,extract,print helper fns.  */
2126
2127 static long
2128 parse_gpuif_prim (opcode, operand, mods, pstr, errmsg)
2129      const txvu_opcode *opcode;
2130      const txvu_operand *operand;
2131      int mods;
2132      char **pstr;
2133      const char **errmsg;
2134 {
2135   char *str = *pstr;
2136   char *start;
2137   long prim;
2138
2139   if (strncasecmp (str, "prim=", 5) != 0)
2140     {
2141       *errmsg = "missing PRIM spec";
2142       return 0;
2143     }
2144   str += 5;
2145   for (start = str; isalnum (*str); ++str)
2146     continue;
2147   if (str == start)
2148     {
2149       *errmsg = "missing PRIM spec";
2150       return 0;
2151     }
2152   /* FIXME: Yes, atoi doesn't do error checking.  Later.  */
2153   prim = atoi (start);
2154   *pstr = str;
2155   return prim;
2156 }
2157
2158 static void
2159 insert_gpuif_prim (opcode, operand, mods, insn, value, errmsg)
2160      const txvu_opcode *opcode;
2161      const txvu_operand *operand;
2162      int mods;
2163      TXVU_INSN *insn;
2164      long value;
2165      const char **errmsg;
2166 {
2167 }
2168
2169 static long
2170 extract_gpuif_prim (opcode, operand, mods, insn, pinvalid)
2171      const txvu_opcode *opcode;
2172      const txvu_operand *operand;
2173      int mods;
2174      TXVU_INSN *insn;
2175      int *pinvalid;
2176 {
2177   return 0;
2178 }
2179
2180 static void
2181 print_gpuif_prim (opcode, operand, mods, insn, info, value)
2182      const txvu_opcode *opcode;
2183      const txvu_operand *operand;
2184      int mods;
2185      TXVU_INSN *insn;
2186      disassemble_info *info;
2187      long value;
2188 {
2189   (*info->fprintf_func) (info->stream, "???");
2190 }
2191
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" },
2208   { 0, 0 }
2209 };
2210
2211 /* Parse a REGS= spec.
2212    The result is ???.  */
2213
2214 static long
2215 parse_gpuif_regs (opcode, operand, mods, pstr, errmsg)
2216      const txvu_opcode *opcode;
2217      const txvu_operand *operand;
2218      int mods;
2219      char **pstr;
2220      const char **errmsg;
2221 {
2222   char *str = *pstr;
2223   char *start;
2224   char c;
2225   int reg;
2226
2227   if (strncasecmp (str, "regs=", 5) != 0)
2228     {
2229       *errmsg = "missing REGS spec";
2230       return 0;
2231     }
2232   str += 5;
2233   SKIP_BLANKS (str);
2234   if (*str != '{')
2235     {
2236       *errmsg = "missing '{' in REGS spec";
2237       return 0;
2238     }
2239   ++str;
2240
2241   while (*str && *str != '}')
2242     {
2243       /* Pick out the register name.  */
2244
2245       SKIP_BLANKS (str);
2246       start = str;
2247       str = scan_symbol (str);
2248       if (str == start)
2249         {
2250           *errmsg = "invalid REG";
2251           return 0;
2252         }
2253
2254       /* Look it up in the table.  */
2255
2256       c = *str;
2257       *str = 0;
2258       reg = lookup_keyword_value (gpuif_regs, start, 0);
2259       *str = c;
2260       if (reg == -1)
2261         {
2262           *errmsg = "invalid REG";
2263           return 0;
2264         }
2265
2266       /* FIXME: save `reg' away somewhere */
2267
2268       /* Prepare for the next one.  */
2269
2270       SKIP_BLANKS (str);
2271       if (*str == ',')
2272         ++str;
2273       else if (*str != '}')
2274         break;
2275     }
2276   if (*str != '}')
2277     {
2278       *errmsg = "missing '{' in REGS spec";
2279       return 0;
2280     }
2281
2282   *pstr = str + 1;
2283   return 0; /* FIXME */
2284 }
2285
2286 static void
2287 insert_gpuif_regs (opcode, operand, mods, insn, value, errmsg)
2288      const txvu_opcode *opcode;
2289      const txvu_operand *operand;
2290      int mods;
2291      TXVU_INSN *insn;
2292      long value;
2293      const char **errmsg;
2294 {
2295 }
2296
2297 static long
2298 extract_gpuif_regs (opcode, operand, mods, insn, pinvalid)
2299      const txvu_opcode *opcode;
2300      const txvu_operand *operand;
2301      int mods;
2302      TXVU_INSN *insn;
2303      int *pinvalid;
2304 {
2305   return 0;
2306 }
2307
2308 static void
2309 print_gpuif_regs (opcode, operand, mods, insn, info, value)
2310      const txvu_opcode *opcode;
2311      const txvu_operand *operand;
2312      int mods;
2313      TXVU_INSN *insn;
2314      disassemble_info *info;
2315      long value;
2316 {
2317   (*info->fprintf_func) (info->stream, "???");
2318 }
2319
2320 static long
2321 parse_gpuif_nloop (opcode, operand, mods, pstr, errmsg)
2322      const txvu_opcode *opcode;
2323      const txvu_operand *operand;
2324      int mods;
2325      char **pstr;
2326      const char **errmsg;
2327 {
2328   char *str = *pstr;
2329   char *start;
2330   char c;
2331   int nloop;
2332
2333   if (strncasecmp (str, "nloop=", 6) != 0)
2334     {
2335       *errmsg = "missing NLOOP spec";
2336       return 0;
2337     }
2338   str += 6;
2339   SKIP_BLANKS (str);
2340   start = str;
2341   str = scan_symbol (str);
2342   if (str == start)
2343     {
2344       *errmsg = "invalid NOOP spec";
2345       return 0;
2346     }
2347   /* FIXME: error checking */
2348   nloop = atoi (start);
2349   *pstr = str;
2350   return nloop;
2351 }
2352
2353 static void
2354 insert_gpuif_nloop (opcode, operand, mods, insn, value, errmsg)
2355      const txvu_opcode *opcode;
2356      const txvu_operand *operand;
2357      int mods;
2358      TXVU_INSN *insn;
2359      long value;
2360      const char **errmsg;
2361 {
2362 }
2363
2364 static long
2365 extract_gpuif_nloop (opcode, operand, mods, insn, pinvalid)
2366      const txvu_opcode *opcode;
2367      const txvu_operand *operand;
2368      int mods;
2369      TXVU_INSN *insn;
2370      int *pinvalid;
2371 {
2372   return 0;
2373 }
2374
2375 static void
2376 print_gpuif_nloop (opcode, operand, mods, insn, info, value)
2377      const txvu_opcode *opcode;
2378      const txvu_operand *operand;
2379      int mods;
2380      TXVU_INSN *insn;
2381      disassemble_info *info;
2382      long value;
2383 {
2384   (*info->fprintf_func) (info->stream, "???");
2385 }
2386
2387 static long
2388 parse_gpuif_eop (opcode, operand, mods, pstr, errmsg)
2389      const txvu_opcode *opcode;
2390      const txvu_operand *operand;
2391      int mods;
2392      char **pstr;
2393      const char **errmsg;
2394 {
2395   if (strncasecmp (*pstr, "eop", 3) == 0)
2396     {
2397       *pstr += 3;
2398       return 1;
2399     }
2400   *errmsg = "missing `EOP'";
2401   return 0;
2402 }
2403
2404 static void
2405 insert_gpuif_eop (opcode, operand, mods, insn, value, errmsg)
2406      const txvu_opcode *opcode;
2407      const txvu_operand *operand;
2408      int mods;
2409      TXVU_INSN *insn;
2410      long value;
2411      const char **errmsg;
2412 {
2413 }
2414
2415 static long
2416 extract_gpuif_eop (opcode, operand, mods, insn, pinvalid)
2417      const txvu_opcode *opcode;
2418      const txvu_operand *operand;
2419      int mods;
2420      TXVU_INSN *insn;
2421      int *pinvalid;
2422 {
2423   return 0;
2424 }
2425
2426 static void
2427 print_gpuif_eop (opcode, operand, mods, insn, info, value)
2428      const txvu_opcode *opcode;
2429      const txvu_operand *operand;
2430      int mods;
2431      TXVU_INSN *insn;
2432      disassemble_info *info;
2433      long value;
2434 {
2435   (*info->fprintf_func) (info->stream, "???");
2436 }
2437 \f
2438 /* Init fns.
2439    These are called before doing each of the respective activities.  */
2440
2441 /* Called by the assembler before parsing an instruction.  */
2442
2443 void
2444 txvu_opcode_init_parse ()
2445 {
2446   state_vu_mnemonic_dest = -1;
2447   state_vu_mnemonic_bc = -1;
2448   state_pke_varlen_p = -1;
2449   state_pke_len = -1;
2450   state_dma_operand_count_p = -1;
2451 }
2452
2453 /*
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
2459 */
2460 int
2461 txvu_dma_operand_count( action)
2462 {
2463     int result = state_dma_operand_count;
2464
2465     if( action == 0)
2466         state_dma_operand_count = 0;
2467     else if( action > 0)
2468         state_dma_operand_count_p = 1;
2469
2470     return result;
2471 }
2472
2473 /* Called by the disassembler before printing an instruction.  */
2474
2475 void
2476 txvu_opcode_init_print ()
2477 {
2478   state_vu_mnemonic_dest = -1;
2479   state_vu_mnemonic_bc = -1;
2480   state_pke_varlen_p = -1;
2481   state_pke_len = -1;
2482 }
2483 \f
2484 /* Indexed by first letter of opcode.  Points to chain of opcodes with same
2485    first letter.  */
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];
2489
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];
2493 \f
2494 /* Initialize any tables that need it.
2495    Must be called once at start up (or when first needed).
2496
2497    FLAGS is currently unused but is intended to control initialization.  */
2498
2499 void
2500 txvu_opcode_init_tables (flags)
2501      int flags;
2502 {
2503   static int init_p = 0;
2504
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
2507      once though.  */
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).  */
2510   if (!init_p)
2511     {
2512       int i,n;
2513
2514       /* Upper VU table.  */
2515
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)
2520         {
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);
2523
2524           txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash];
2525           upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i];
2526
2527           txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash];
2528           upper_icode_map[icode_hash] = &txvu_upper_opcodes[i];
2529         }
2530
2531       /* Lower VU table.  */
2532
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)
2537         {
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);
2540
2541           txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash];
2542           lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i];
2543
2544           txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash];
2545           lower_icode_map[icode_hash] = &txvu_lower_opcodes[i];
2546         }
2547
2548       /* FIXME: We just hash everything to the same value for the rest.
2549          Quick hack while other things are worked on.  */
2550
2551       /* PKE table.  */
2552
2553       for (i = pke_opcodes_count - 2; i >= 0; --i)
2554         {
2555           pke_opcodes[i].next_asm = & pke_opcodes[i+1];
2556           pke_opcodes[i].next_dis = & pke_opcodes[i+1];
2557         }
2558
2559       /* DMA table.  */
2560
2561       for (i = dma_opcodes_count - 2; i >= 0; --i)
2562         {
2563           dma_opcodes[i].next_asm = & dma_opcodes[i+1];
2564           dma_opcodes[i].next_dis = & dma_opcodes[i+1];
2565         }
2566
2567       /* GPUIF table.  */
2568
2569       for (i = gpuif_opcodes_count - 2; i >= 0; --i)
2570         {
2571           gpuif_opcodes[i].next_asm = & gpuif_opcodes[i+1];
2572           gpuif_opcodes[i].next_dis = & gpuif_opcodes[i+1];
2573         }
2574
2575       init_p = 1;
2576     }
2577 }
2578
2579 /* Return the first insn in the chain for assembling upper INSN.  */
2580
2581 const txvu_opcode *
2582 txvu_upper_opcode_lookup_asm (insn)
2583      const char *insn;
2584 {
2585   return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)];
2586 }
2587
2588 /* Return the first insn in the chain for disassembling upper INSN.  */
2589
2590 const txvu_opcode *
2591 txvu_upper_opcode_lookup_dis (insn)
2592      TXVU_INSN insn;
2593 {
2594   return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)];
2595 }
2596
2597 /* Return the first insn in the chain for assembling lower INSN.  */
2598
2599 const txvu_opcode *
2600 txvu_lower_opcode_lookup_asm (insn)
2601      const char *insn;
2602 {
2603   return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)];
2604 }
2605
2606 /* Return the first insn in the chain for disassembling lower INSN.  */
2607
2608 const txvu_opcode *
2609 txvu_lower_opcode_lookup_dis (insn)
2610      TXVU_INSN insn;
2611 {
2612   return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)];
2613 }
2614
2615 /* Return the first insn in the chain for assembling lower INSN.  */
2616
2617 const txvu_opcode *
2618 pke_opcode_lookup_asm (insn)
2619      const char *insn;
2620 {
2621   return &pke_opcodes[0];
2622 }
2623
2624 /* Return the first insn in the chain for disassembling lower INSN.  */
2625
2626 const txvu_opcode *
2627 pke_opcode_lookup_dis (insn)
2628      TXVU_INSN insn;
2629 {
2630   return &pke_opcodes[0];
2631 }
2632
2633 /* Return the first insn in the chain for assembling lower INSN.  */
2634
2635 const txvu_opcode *
2636 dma_opcode_lookup_asm (insn)
2637      const char *insn;
2638 {
2639   return &dma_opcodes[0];
2640 }
2641
2642 /* Return the first insn in the chain for disassembling lower INSN.  */
2643
2644 const txvu_opcode *
2645 dma_opcode_lookup_dis (insn)
2646      TXVU_INSN insn;
2647 {
2648   return &dma_opcodes[0];
2649 }
2650
2651 /* Return the first insn in the chain for assembling lower INSN.  */
2652
2653 const txvu_opcode *
2654 gpuif_opcode_lookup_asm (insn)
2655      const char *insn;
2656 {
2657   return &gpuif_opcodes[0];
2658 }
2659
2660 /* Return the first insn in the chain for disassembling lower INSN.  */
2661
2662 const txvu_opcode *
2663 gpuif_opcode_lookup_dis (insn)
2664      TXVU_INSN insn;
2665 {
2666   return &gpuif_opcodes[0];
2667 }
2668 \f
2669 /* Misc. utilities.  */
2670
2671 /* Scan a symbol and return a pointer to one past the end.  */
2672
2673 static char *
2674 scan_symbol (sym)
2675      char *sym;
2676 {
2677   while (*sym && issymchar (*sym))
2678     ++sym;
2679   return sym;
2680 }
2681
2682 /* Given a keyword, look up its value, or -1 if not found.  */
2683
2684 static int
2685 lookup_keyword_value (table, name, case_sensitive_p)
2686      const keyword *table;
2687      const char *name;
2688      int case_sensitive_p;
2689 {
2690   const keyword *p;
2691
2692   if (case_sensitive_p)
2693     {
2694       for (p = table; p->name; ++p)
2695         if (strcmp (name, p->name) == 0)
2696           return p->value;
2697     }
2698   else
2699     {
2700       for (p = table; p->name; ++p)
2701         if (strcasecmp (name, p->name) == 0)
2702           return p->value;
2703     }
2704
2705   return -1;
2706 }
2707
2708 /* Given a keyword's value, look up its name, or NULL if not found.  */
2709
2710 static const char *
2711 lookup_keyword_name (table, value)
2712      const keyword *table;
2713      int value;
2714 {
2715   const keyword *p;
2716
2717   for (p = table; p->name; ++p)
2718     if (value == p->value)
2719       return p->name;
2720
2721   return NULL;
2722 }