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