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