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 | ||
33 | /* ??? One can argue it's preferable to have the PARSE_FN support in tc-vxvu.c | |
34 | and the PRINT_FN support in txvu-dis.c. For this project I like having | |
35 | them all in one place. */ | |
36 | ||
37 | #define PARSE_FN(fn) \ | |
38 | static long CONCAT2 (parse_,fn) \ | |
39 | PARAMS ((char **, const char **)); | |
40 | #define INSERT_FN(fn) \ | |
41 | static TXVU_INSN CONCAT2 (insert_,fn) \ | |
42 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
43 | int, long, const char **)) | |
44 | #define EXTRACT_FN(fn) \ | |
45 | static long CONCAT2 (extract_,fn) \ | |
46 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
47 | int, int *)) | |
48 | #define PRINT_FN(fn) \ | |
49 | static void CONCAT2 (print_,fn) \ | |
50 | PARAMS ((disassemble_info *, TXVU_INSN, long)); | |
51 | ||
52 | PARSE_FN (dotdest); | |
71af45ec DE |
53 | INSERT_FN (dotdest); |
54 | EXTRACT_FN (dotdest); | |
54cc8ed4 DE |
55 | PRINT_FN (dotdest); |
56 | ||
71af45ec DE |
57 | PARSE_FN (vfreg); |
58 | PRINT_FN (vfreg); | |
54cc8ed4 | 59 | |
3f897263 DE |
60 | PARSE_FN (bc); |
61 | PRINT_FN (bc); | |
62 | ||
0b988d39 DE |
63 | PARSE_FN (bcftreg); |
64 | PRINT_FN (bcftreg); | |
3f897263 DE |
65 | |
66 | PARSE_FN (accdest); | |
67 | PRINT_FN (accdest); | |
68 | ||
69 | PARSE_FN (xyz); | |
70 | ||
0b988d39 DE |
71 | PARSE_FN (ireg); |
72 | PRINT_FN (ireg); | |
73 | ||
74 | PARSE_FN (freg); | |
75 | PRINT_FN (freg); | |
76 | ||
77 | PARSE_FN (ffstreg); | |
78 | INSERT_FN (ffstreg); | |
79 | EXTRACT_FN (ffstreg); | |
80 | PRINT_FN (ffstreg); | |
81 | ||
82 | PARSE_FN (vi01); | |
83 | PRINT_FN (vi01); | |
84 | ||
85 | INSERT_FN (limm12); | |
86 | EXTRACT_FN (limm12); | |
87 | ||
3f897263 | 88 | /* Various types of TXVU operands, including insn suffixes. |
54cc8ed4 DE |
89 | |
90 | Fields are: | |
91 | ||
92 | BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN | |
93 | ||
94 | Operand values are 128 + table index. This allows ASCII chars to be | |
95 | included in the syntax spec. */ | |
96 | ||
97 | const struct txvu_operand txvu_operands[] = | |
98 | { | |
3f897263 | 99 | /* place holder (??? not sure if needed) */ |
54cc8ed4 DE |
100 | #define UNUSED 128 |
101 | { 0 }, | |
102 | ||
0b988d39 DE |
103 | /* Upper word operands. */ |
104 | ||
3f897263 | 105 | /* Destination indicator, with leading '.'. */ |
0b988d39 | 106 | #define UDOTDEST (UNUSED + 1) |
54cc8ed4 | 107 | { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX, |
71af45ec | 108 | parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest }, |
54cc8ed4 | 109 | |
3f897263 | 110 | /* ft reg */ |
0b988d39 | 111 | #define UVFTREG (UDOTDEST + 1) |
71af45ec | 112 | { 5, TXVU_SHIFT_FTREG, 0, parse_vfreg, 0, 0, print_vfreg }, |
54cc8ed4 | 113 | |
3f897263 | 114 | /* fs reg */ |
0b988d39 | 115 | #define UVFSREG (UVFTREG + 1) |
71af45ec | 116 | { 5, TXVU_SHIFT_FSREG, 0, parse_vfreg, 0, 0, print_vfreg }, |
54cc8ed4 | 117 | |
3f897263 | 118 | /* fd reg */ |
0b988d39 | 119 | #define UVFDREG (UVFSREG + 1) |
71af45ec | 120 | { 5, TXVU_SHIFT_FDREG, 0, parse_vfreg, 0, 0, print_vfreg }, |
54cc8ed4 | 121 | |
3f897263 | 122 | /* broadcast */ |
0b988d39 | 123 | #define UBC (UVFDREG + 1) |
3f897263 DE |
124 | { 2, 0, 0, parse_bc, 0, 0, print_bc }, |
125 | ||
126 | /* ftreg in broadcast case */ | |
0b988d39 DE |
127 | #define UBCFTREG (UBC + 1) |
128 | { 5, TXVU_SHIFT_FTREG, 0, parse_bcftreg, 0, 0, print_bcftreg }, | |
3f897263 DE |
129 | |
130 | /* accumulator dest */ | |
0b988d39 | 131 | #define UACCDEST (UBCFTREG + 1) |
3f897263 DE |
132 | { 0, 0, TXVU_OPERAND_FAKE, parse_accdest, 0, 0, print_accdest }, |
133 | ||
134 | /* The XYZ operand is a fake one that is used to ensure only "xyz" is | |
135 | specified. It simplifies the opmula and opmsub entries. */ | |
0b988d39 | 136 | #define UXYZ (UACCDEST + 1) |
3f897263 DE |
137 | { 0, 0, TXVU_OPERAND_FAKE, parse_xyz, 0, 0, 0 }, |
138 | ||
0b988d39 DE |
139 | /* Lower word operands. */ |
140 | ||
141 | /* 11 bit immediate. */ | |
142 | #define LIMM11 (UXYZ + 1) | |
143 | { 11, 0, 0, 0, 0, 0, 0 }, | |
144 | ||
145 | /* IS register. */ | |
146 | #define LISREG (LIMM11 + 1) | |
147 | { 5, 11, 0, parse_ireg, 0, 0, print_ireg }, | |
148 | ||
149 | /* IT register. */ | |
150 | #define LITREG (LISREG + 1) | |
151 | { 5, 16, 0, parse_ireg, 0, 0, print_ireg }, | |
152 | ||
153 | /* FS reg, with FSF field selector. */ | |
154 | #define LFSFFSREG (LITREG + 1) | |
155 | { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg }, | |
156 | ||
157 | /* FS reg, no selector (choice of x,y,z,w is provided by opcode). */ | |
158 | #define LFSREG (LFSFFSREG + 1) | |
159 | { 5, 11, 0, parse_freg, 0, 0, print_freg }, | |
160 | ||
161 | /* FT reg, with FTF field selector. */ | |
162 | #define LFTFFTREG (LFSREG + 1) | |
163 | { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg }, | |
164 | ||
165 | /* VI01 register. */ | |
166 | #define LVI01 (LFTFFTREG + 1) | |
167 | { 0, 0, TXVU_OPERAND_FAKE, parse_vi01, 0, 0, print_vi01 }, | |
168 | ||
169 | /* 24 bit immediate. */ | |
170 | #define LIMM24 (LVI01 + 1) | |
171 | { 24, 0, 0, 0, 0, 0, 0 }, | |
172 | ||
173 | /* 12 bit immediate, split into 1 and 11 bit pieces. */ | |
174 | #define LIMM12 (LIMM24 + 1) | |
175 | { 12, 0, 0, 0, insert_limm12, extract_limm12, 0 }, | |
176 | ||
54cc8ed4 DE |
177 | /* end of list place holder */ |
178 | { 0 } | |
179 | }; | |
180 | \f | |
181 | /* Macros to put a field's value into the right place. */ | |
3f897263 DE |
182 | /* FIXME: If assembler needs these, move to opcode/txvu.h. */ |
183 | ||
0b988d39 DE |
184 | /* value X, B bits, shift S */ |
185 | #define R(x,b,s) (((x) & ((1 << (b)) - 1)) << (s)) | |
186 | ||
187 | /* Upper instruction Value macros. */ | |
54cc8ed4 | 188 | |
3f897263 | 189 | /* Upper Flag bits. */ |
0b988d39 | 190 | #define VUF(x) R ((x), 5, 27) |
3f897263 | 191 | /* Upper REServed two bits next to flag bits. */ |
0b988d39 DE |
192 | #define VURES(x) R ((x), 2, 25) |
193 | /* DEST field. */ | |
194 | #define VUDEST(x) R ((x), 4, 21) | |
195 | /* FT reg field. */ | |
196 | #define VUFT(x) R ((x), 5, TXVU_SHIFT_FTREG) | |
197 | /* FS reg field. */ | |
198 | #define VUFS(x) R ((x), 5, TXVU_SHIFT_FSREG) | |
199 | /* FD reg field. */ | |
200 | #define VUFD(x) R ((x), 5, TXVU_SHIFT_FDREG) | |
201 | /* 4 bit opcode field. */ | |
202 | #define VUOP4(x) R ((x), 4, 2) | |
203 | /* 6 bit opcode field. */ | |
204 | #define VUOP6(x) R ((x), 6, 0) | |
205 | /* 9 bit opcode field. */ | |
206 | #define VUOP9(x) R ((x), 9, 2) | |
207 | /* 11 bit opcode field. */ | |
208 | #define VUOP11(x) R ((x), 11, 0) | |
209 | /* BroadCast field. */ | |
210 | #define VUBC(x) R ((x), 2, 0) | |
211 | ||
212 | /* Field masks. */ | |
213 | #define MUUBITS (VUF (~0) + VURES (~0)) | |
214 | #define MURES VURES (~0) | |
215 | #define MUOP4 VUOP4 (~0) | |
216 | #define MUOP6 VUOP6 (~0) | |
217 | #define MUOP9 VUOP9 (~0) | |
218 | #define MUOP11 VUOP11 (~0) | |
219 | ||
220 | /* Lower instruction Value macros. */ | |
221 | ||
222 | /* 7 bit opcode. */ | |
223 | #define VLOP7(x) R ((x), 7, 25) | |
224 | /* 11 bit opcode. */ | |
225 | #define VLOP11(x) R ((x), 11, 0) | |
226 | /* dest field. */ | |
227 | #define VLDEST(x) R ((x), 4, 21) | |
228 | /* IT reg. */ | |
229 | #define VLIT(x) R ((x), 5, 16) | |
230 | /* IS reg. */ | |
231 | #define VLIS(x) R ((x), 5, 11) | |
232 | /* 11 bit immediate. */ | |
233 | #define VLIMM11(x) R ((x), 11, 0) | |
234 | /* FTF field. */ | |
235 | #define VLFTF(x) R ((x), 2, 23) | |
236 | /* FSF field. */ | |
237 | #define VLFSF(x) R ((x), 2, 21) | |
238 | /* FT reg. */ | |
239 | #define VLFT(x) R ((x), 5, 16) | |
240 | /* FS reg. */ | |
241 | #define VLFS(x) R ((x), 5, 11) | |
242 | ||
243 | /* Field masks. */ | |
244 | #define MLOP7 VLOP7 (~0) | |
245 | #define MLOP11 VLOP11 (~0) | |
246 | #define MLDEST VLDEST (~0) | |
247 | #define MLIT VLIT (~0) | |
248 | #define MLIS VLIS (~0) | |
249 | #define MLIMM11 VLIMM11 (~0) | |
250 | #define MLB24 R (1, 1, 24) | |
251 | /* 12 bit immediates are split into two parts, 1 bit and 11 bits. | |
252 | The upper 1 bit is part of the `dest' field. This mask is for the | |
253 | other 3 bits of the dest field. */ | |
254 | #define MLIMM12TOP R (7, 3, 22) | |
3f897263 DE |
255 | |
256 | /* A space, separates instruction name (mnemonic + mnemonic operands) from operands. */ | |
257 | #define SP ' ' | |
258 | ||
54cc8ed4 DE |
259 | /* TXVU instructions. |
260 | [??? some of these comments are left over from the ARC port from which | |
261 | this code is borrowed, delete in time] | |
262 | ||
263 | Longer versions of insns must appear before shorter ones (if gas sees | |
264 | "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is | |
265 | junk). This isn't necessary for `ld' because of the trailing ']'. | |
266 | ||
267 | Instructions that are really macros based on other insns must appear | |
268 | before the real insn so they're chosen when disassembling. Eg: The `mov' | |
269 | insn is really the `and' insn. | |
270 | ||
271 | This table is best viewed on a wide screen (161 columns). I'd prefer to | |
272 | keep it this way. The rest of the file, however, should be viewable on an | |
273 | 80 column terminal. */ | |
274 | ||
275 | /* ??? This table also includes macros: asl, lsl, and mov. The ppc port has | |
276 | a more general facility for dealing with macros which could be used if | |
277 | we need to. */ | |
278 | ||
279 | /* These tables can't be `const' because members `next_asm' and `next_dis' are | |
280 | computed at run-time. We could split this into two, as that would put the | |
281 | constant stuff into a readonly section. */ | |
282 | ||
283 | struct txvu_opcode txvu_upper_opcodes[] = { | |
284 | ||
285 | /* Macros appear first. */ | |
286 | /* ??? Any aliases? */ | |
0b988d39 | 287 | /* FIXME: When close to being finished, clean up by aligning fields. */ |
54cc8ed4 | 288 | |
3f897263 | 289 | /* The rest of these needn't be sorted, but it helps to find them if they are. */ |
0b988d39 DE |
290 | { "abs", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x1fd) }, |
291 | { "add", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x28) }, | |
292 | { "addi", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x22) }, | |
293 | { "addq", { UDOTDEST, SP, UVFDREG, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x20) }, | |
294 | { "add", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (0) }, | |
295 | { "adda", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG }, MURES + MUOP11, VUOP11 (0x2bc) }, | |
296 | { "addai", { UDOTDEST, SP, UACCDEST, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x23e) }, | |
297 | { "addaq", { UDOTDEST, SP, UACCDEST, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x23c) }, | |
298 | { "adda", { UBC, UDOTDEST, SP, UACCDEST, UVFSREG, UBCFTREG }, MURES + MUOP9, VUOP9 (0xf) }, | |
299 | { "clip", { UDOTDEST, SP, UVFSREG }, MURES + VUDEST (~0) + VUFT (~0) + MUOP11, VUDEST (0xf) + VUOP11 (0x1ff) }, | |
300 | { "ftoi0", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x17c) }, | |
301 | { "ftoi4", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x17d) }, | |
302 | { "ftoi12", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x17e) }, | |
303 | { "ftoi15", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x17f) }, | |
304 | { "itof0", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x13c) }, | |
305 | { "itof4", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x13d) }, | |
306 | { "itof12", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x13e) }, | |
307 | { "itof15", { UDOTDEST, SP, UVFTREG, UVFSREG }, MURES + MUOP11, VUOP11 (0x13f) }, | |
308 | { "madd", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x29) }, | |
309 | { "maddi", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x23) }, | |
310 | { "maddq", { UDOTDEST, SP, UVFDREG, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x21) }, | |
311 | { "madd", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + MUOP4, VUOP4 (0x2) }, | |
312 | { "madda", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG }, MURES + MUOP11, VUOP11 (0x2bd) }, | |
313 | { "maddai", { UDOTDEST, SP, UACCDEST, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x23f) }, | |
314 | { "maddaq", { UDOTDEST, SP, UACCDEST, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x23d) }, | |
315 | { "madda", { UBC, UDOTDEST, SP, UACCDEST, UVFSREG, UBCFTREG }, MURES + MUOP9, VUOP9 (0x2f) }, | |
316 | { "max", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x2b) }, | |
317 | { "maxi", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x2d) }, | |
318 | { "max", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + MUOP4, VUOP4 (0x4) }, | |
3f897263 | 319 | /* FIXME: mini or min? */ |
0b988d39 DE |
320 | { "mini", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x2f) }, |
321 | { "mini", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x1f) }, | |
322 | { "mini", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + MUOP4, VUOP4 (0x5) }, | |
323 | { "msub", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x2d) }, | |
324 | { "msubi", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x27) }, | |
325 | { "msubq", { UDOTDEST, SP, UVFDREG, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x25) }, | |
326 | { "msub", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + MUOP4, VUOP4 (0x3) }, | |
327 | { "msuba", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG }, MURES + MUOP11, VUOP11 (0x2fd) }, | |
328 | { "msubai", { UDOTDEST, SP, UACCDEST, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x27f) }, | |
329 | { "msubaq", { UDOTDEST, SP, UACCDEST, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x27d) }, | |
330 | { "msuba", { UBC, UDOTDEST, SP, UACCDEST, UVFSREG, UBCFTREG }, MURES + MUOP9, VUOP9 (0x3f) }, | |
331 | { "mul", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x2a) }, | |
332 | { "muli", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x1e) }, | |
333 | { "mulq", { UDOTDEST, SP, UVFDREG, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x1c) }, | |
334 | { "mul", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (6) }, | |
335 | { "mula", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG }, MURES + MUOP11, VUOP11 (0x2be) }, | |
336 | { "mulai", { UDOTDEST, SP, UACCDEST, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x1fe) }, | |
337 | { "mulaq", { UDOTDEST, SP, UACCDEST, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x1fc) }, | |
338 | { "mula", { UBC, UDOTDEST, SP, UACCDEST, UVFSREG, UBCFTREG }, MURES + MUOP9, VUOP9 (0x6f) }, | |
339 | { "nop", { 0 }, MURES + VUDEST (~0) + VUFT (~0) + VUFS (~0) + MUOP11, VUOP11 (0x2ff) }, | |
340 | { "opmula", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG, UXYZ }, MURES + MUOP11, VUOP11 (0x2fe) }, | |
341 | { "opmsub", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG, UXYZ }, MURES + MUOP6, VUOP6 (0x2e) }, | |
342 | { "sub", { UDOTDEST, SP, UVFDREG, UVFSREG, UVFTREG }, MURES + MUOP6, VUOP6 (0x2c) }, | |
343 | { "subi", { UDOTDEST, SP, UVFDREG, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x26) }, | |
344 | { "subq", { UDOTDEST, SP, UVFDREG, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP6, VUOP6 (0x24) }, | |
345 | { "sub", { UBC, UDOTDEST, SP, UVFDREG, UVFSREG, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (1) }, | |
346 | { "suba", { UDOTDEST, SP, UACCDEST, UVFSREG, UVFTREG }, MURES + MUOP11, VUOP11 (0x2fc) }, | |
347 | { "subai", { UDOTDEST, SP, UACCDEST, UVFSREG, 'i' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x27e) }, | |
348 | { "subaq", { UDOTDEST, SP, UACCDEST, UVFSREG, 'q' }, MURES + VUFT (~0) + MUOP11, VUOP11 (0x27c) }, | |
349 | { "suba", { UBC, UDOTDEST, SP, UACCDEST, UVFSREG, UBCFTREG }, MURES + MUOP9, VUOP9 (0x1f) } | |
54cc8ed4 DE |
350 | }; |
351 | const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_opcodes[0]); | |
352 | ||
353 | struct txvu_opcode txvu_lower_opcodes[] = { | |
354 | ||
355 | /* Macros appear first. */ | |
356 | /* ??? Any aliases? */ | |
357 | ||
0b988d39 DE |
358 | /* The rest of these needn't be sorted, but it helps to find them if they are. */ |
359 | { "b", { SP, LIMM11 }, MLOP7 + MLDEST + MLIT + MLIS, VLOP7 (0x20) }, | |
360 | { "bal", { SP, LITREG, LIMM11 }, MLOP7 + MLDEST + MLIS, VLOP7 (0x21) }, | |
361 | { "div", { 'q', LFSFFSREG, LFTFFTREG }, MLOP7 + MLOP11, VLOP7 (0x40) + VLOP11 (0x3bc) }, | |
362 | { "eatan", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) }, | |
363 | { "eatanxy", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x77c) }, | |
364 | { "eatanxz", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x77d) }, | |
365 | { "eexp", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) }, | |
366 | { "eleng", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x74e) }, | |
367 | { "ercpr", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) }, | |
368 | { "erleng", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x73f) }, | |
369 | { "ersadd", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x73d) }, | |
370 | { "ersqrt", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) }, | |
371 | { "esadd", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x73c) }, | |
372 | { "esin", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) }, | |
373 | { "esqrt", { 'p', LFSFFSREG }, MLOP7 + VLFTF (~0) + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) }, | |
374 | { "esum", { 'p', LFSREG }, MLOP7 + MLDEST + VLFT (~0) + MLOP11, VLOP7 (0x40) + VLDEST (0xf) + VLOP11 (0x77e) }, | |
375 | { "fcand", { LVI01, LIMM24 }, MLOP7 + MLB24, VLOP7 (0x12) }, | |
376 | { "fceq", { LVI01, LIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) }, | |
377 | { "fcget", { LITREG }, MLOP7 + MLDEST + MLIS + MLIMM11, VLOP7 (0x1c) }, | |
378 | { "fcor", { LVI01, LIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) }, | |
379 | { "fcset", { LVI01, LIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) }, | |
380 | { "fmand", { LITREG, LISREG }, MLOP7 + MLDEST + MLIMM11, VLOP7 (0x1a) }, | |
381 | { "fmeq", { LITREG, LISREG }, MLOP7 + MLDEST + MLIMM11, VLOP7 (0x18) }, | |
382 | { "fmor", { LITREG, LISREG }, MLOP7 + MLDEST + MLIMM11, VLOP7 (0x1b) }, | |
383 | { "fsand", { LITREG, LIMM12 }, MLOP7 + MLIMM12TOP + MLIS, VLOP7 (0x16) }, | |
384 | { "fseq", { LITREG, LIMM12 }, MLOP7 + MLIMM12TOP + MLIS, VLOP7 (0x14) }, | |
385 | { "fsor", { LITREG, LIMM12 }, MLOP7 + MLIMM12TOP + MLIS, VLOP7 (0x17) }, | |
386 | { "fsset", { LITREG, LIMM12 }, MLOP7 + MLIMM12TOP + MLIS, VLOP7 (0x15) }, | |
387 | { "waitp", { 0 }, 0xffffffff, 0x800007bf }, | |
388 | { "waitq", { 0 }, 0xffffffff, 0x800003bf }, | |
54cc8ed4 DE |
389 | }; |
390 | const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_opcodes[0]); | |
391 | ||
392 | /* Indexed by first letter of opcode. Points to chain of opcodes with same | |
393 | first letter. */ | |
394 | /* ??? One can certainly use a better hash. Later. */ | |
395 | static struct txvu_opcode *upper_opcode_map[26 + 1]; | |
396 | static struct txvu_opcode *lower_opcode_map[26 + 1]; | |
397 | ||
398 | /* Indexed by insn code. Points to chain of opcodes with same insn code. */ | |
399 | static struct txvu_opcode *upper_icode_map[64]; | |
400 | static struct txvu_opcode *lower_icode_map[64]; | |
401 | \f | |
402 | /* Initialize any tables that need it. | |
403 | Must be called once at start up (or when first needed). | |
404 | ||
405 | FLAGS is currently unused but is intended to control initialization. */ | |
406 | ||
407 | void | |
408 | txvu_opcode_init_tables (flags) | |
409 | int flags; | |
410 | { | |
411 | static int init_p = 0; | |
412 | ||
413 | /* We may be intentionally called more than once (for example gdb will call | |
414 | us each time the user switches cpu). These tables only need to be init'd | |
415 | once though. */ | |
416 | /* ??? We can remove the need for txvu_opcode_supported by taking it into | |
417 | account here, but I'm not sure I want to do that yet (if ever). */ | |
418 | if (!init_p) | |
419 | { | |
420 | int i,n; | |
421 | ||
422 | memset (upper_opcode_map, 0, sizeof (upper_opcode_map)); | |
423 | memset (upper_icode_map, 0, sizeof (upper_icode_map)); | |
424 | ||
425 | /* Scan the table backwards so macros appear at the front. */ | |
426 | for (i = txvu_upper_opcodes_count - 1; i >= 0; --i) | |
427 | { | |
428 | int opcode_hash = TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes[i].mnemonic); | |
429 | int icode_hash = TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes[i].value); | |
430 | ||
431 | txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash]; | |
432 | upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i]; | |
433 | ||
434 | txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash]; | |
435 | upper_icode_map[icode_hash] = &txvu_upper_opcodes[i]; | |
436 | } | |
437 | ||
438 | memset (lower_opcode_map, 0, sizeof (lower_opcode_map)); | |
439 | memset (lower_icode_map, 0, sizeof (lower_icode_map)); | |
440 | ||
441 | /* Scan the table backwards so macros appear at the front. */ | |
442 | for (i = txvu_lower_opcodes_count - 1; i >= 0; --i) | |
443 | { | |
444 | int opcode_hash = TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes[i].mnemonic); | |
445 | int icode_hash = TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes[i].value); | |
446 | ||
447 | txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash]; | |
448 | lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i]; | |
449 | ||
450 | txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash]; | |
451 | lower_icode_map[icode_hash] = &txvu_lower_opcodes[i]; | |
452 | } | |
453 | ||
454 | init_p = 1; | |
455 | } | |
456 | } | |
457 | ||
458 | /* Return the first insn in the chain for assembling upper INSN. */ | |
459 | ||
460 | const struct txvu_opcode * | |
461 | txvu_upper_opcode_lookup_asm (insn) | |
462 | const char *insn; | |
463 | { | |
464 | return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)]; | |
465 | } | |
466 | ||
467 | /* Return the first insn in the chain for assembling lower INSN. */ | |
468 | ||
469 | const struct txvu_opcode * | |
470 | txvu_lower_opcode_lookup_asm (insn) | |
471 | const char *insn; | |
472 | { | |
473 | return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)]; | |
474 | } | |
475 | ||
476 | /* Return the first insn in the chain for disassembling upper INSN. */ | |
477 | ||
478 | const struct txvu_opcode * | |
479 | txvu_upper_opcode_lookup_dis (insn) | |
480 | TXVU_INSN insn; | |
481 | { | |
482 | return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)]; | |
483 | } | |
484 | ||
485 | /* Return the first insn in the chain for disassembling lower INSN. */ | |
486 | ||
487 | const struct txvu_opcode * | |
488 | txvu_lower_opcode_lookup_dis (insn) | |
489 | TXVU_INSN insn; | |
490 | { | |
491 | return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)]; | |
492 | } | |
493 | \f | |
494 | /* Value of DEST in use. | |
71af45ec | 495 | Each of the registers must specify the same value as the opcode. |
54cc8ed4 DE |
496 | ??? Perhaps remove the duplication? */ |
497 | static int dest; | |
3f897263 DE |
498 | |
499 | /* Value of BC to use. | |
500 | The register specified for the ftreg must match the broadcast register | |
501 | specified in the opcode. */ | |
502 | static int bc; | |
54cc8ed4 DE |
503 | \f |
504 | /* Init fns. | |
505 | These are called before doing each of the respective activities. */ | |
506 | ||
507 | /* Called by the assembler before parsing an instruction. */ | |
508 | ||
509 | void | |
510 | txvu_opcode_init_parse () | |
511 | { | |
512 | dest = -1; | |
3f897263 | 513 | bc = -1; |
54cc8ed4 DE |
514 | } |
515 | ||
516 | /* Called by the disassembler before printing an instruction. */ | |
517 | ||
518 | void | |
519 | txvu_opcode_init_print () | |
520 | { | |
521 | dest = -1; | |
3f897263 | 522 | bc = -1; |
54cc8ed4 DE |
523 | } |
524 | \f | |
525 | /* 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 | ||
71af45ec DE |
529 | /* 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 | ||
54cc8ed4 | 534 | static long |
71af45ec | 535 | parse_dest (pstr) |
54cc8ed4 | 536 | char **pstr; |
54cc8ed4 DE |
537 | { |
538 | long dest = 0; | |
539 | ||
54cc8ed4 DE |
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; | |
71af45ec | 548 | default : return dest; |
54cc8ed4 DE |
549 | } |
550 | ++*pstr; | |
551 | } | |
552 | ||
71af45ec DE |
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 | } | |
54cc8ed4 DE |
576 | *errmsg = NULL; |
577 | return dest; | |
578 | } | |
579 | ||
71af45ec DE |
580 | static TXVU_INSN |
581 | insert_dotdest (insn, operand, mods, value, errmsg) | |
582 | TXVU_INSN insn; | |
583 | const struct txvu_operand *operand; | |
584 | int mods; | |
585 | long value; | |
586 | const char **errmsg; | |
587 | { | |
588 | /* Record the DEST value in use so the register parser can use it. */ | |
589 | dest = value; | |
590 | if (errmsg) | |
591 | *errmsg = NULL; | |
592 | return insn |= value << operand->shift; | |
593 | } | |
594 | ||
595 | static long | |
596 | extract_dotdest (insn, operand, mods, pinvalid) | |
597 | TXVU_INSN insn; | |
598 | const struct txvu_operand *operand; | |
599 | int mods; | |
600 | int *pinvalid; | |
601 | { | |
602 | /* Record the DEST value in use so the register printer can use it. */ | |
603 | dest = (insn >> operand->shift) & ((1 << operand->bits) - 1); | |
604 | return dest; | |
605 | } | |
606 | ||
54cc8ed4 | 607 | static void |
71af45ec | 608 | print_dest (info, insn, value) |
54cc8ed4 DE |
609 | disassemble_info *info; |
610 | TXVU_INSN insn; | |
611 | long value; | |
612 | { | |
54cc8ed4 DE |
613 | if (value & TXVU_DEST_X) |
614 | (*info->fprintf_func) (info->stream, "x"); | |
615 | if (value & TXVU_DEST_Y) | |
616 | (*info->fprintf_func) (info->stream, "y"); | |
617 | if (value & TXVU_DEST_Z) | |
618 | (*info->fprintf_func) (info->stream, "z"); | |
619 | if (value & TXVU_DEST_W) | |
620 | (*info->fprintf_func) (info->stream, "w"); | |
621 | } | |
71af45ec DE |
622 | |
623 | static void | |
624 | print_dotdest (info, insn, value) | |
625 | disassemble_info *info; | |
626 | TXVU_INSN insn; | |
627 | long value; | |
628 | { | |
629 | (*info->fprintf_func) (info->stream, "."); | |
630 | print_dest (info, insn, value); | |
631 | } | |
54cc8ed4 DE |
632 | \f |
633 | static long | |
71af45ec | 634 | parse_vfreg (pstr, errmsg) |
54cc8ed4 DE |
635 | char **pstr; |
636 | const char **errmsg; | |
637 | { | |
638 | char *str = *pstr; | |
639 | char *start; | |
640 | long reg; | |
71af45ec | 641 | int reg_dest; |
54cc8ed4 DE |
642 | |
643 | if (tolower (str[0]) != 'v' | |
644 | || tolower (str[1]) != 'f') | |
645 | { | |
646 | *errmsg = "unknown register"; | |
647 | return 0; | |
648 | } | |
649 | ||
650 | /* FIXME: quick hack until the framework works. */ | |
651 | start = str = str + 2; | |
652 | while (*str && isdigit (*str)) | |
653 | ++str; | |
654 | reg = atoi (start); | |
71af45ec DE |
655 | reg_dest = parse_dest (&str); |
656 | if (reg_dest == 0 || isalnum (*str)) | |
657 | { | |
658 | *errmsg = "invalid `dest'"; | |
659 | return 0; | |
660 | } | |
661 | if (reg_dest != dest) | |
662 | { | |
663 | *errmsg = "register `dest' does not match instruction `dest'"; | |
664 | return 0; | |
665 | } | |
54cc8ed4 DE |
666 | *pstr = str; |
667 | *errmsg = NULL; | |
668 | return reg; | |
669 | } | |
670 | ||
671 | static void | |
71af45ec | 672 | print_vfreg (info, insn, value) |
54cc8ed4 DE |
673 | disassemble_info *info; |
674 | TXVU_INSN insn; | |
675 | long value; | |
676 | { | |
677 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
71af45ec | 678 | print_dest (info, insn, dest); |
54cc8ed4 | 679 | } |
3f897263 DE |
680 | \f |
681 | /* Broadcast handling. */ | |
682 | ||
683 | static long | |
684 | parse_bc (pstr, errmsg) | |
685 | char **pstr; | |
686 | const char **errmsg; | |
687 | { | |
688 | long dest = 0; | |
689 | ||
690 | switch (**pstr) | |
691 | { | |
692 | case 'x' : case 'X' : dest = TXVU_BC_X; break; | |
693 | case 'y' : case 'Y' : dest = TXVU_BC_Y; break; | |
694 | case 'z' : case 'Z' : dest = TXVU_BC_Z; break; | |
695 | case 'w' : case 'W' : dest = TXVU_BC_W; break; | |
696 | default : *errmsg = "invalid `bc'"; return 0; | |
697 | } | |
698 | ++*pstr; | |
699 | ||
700 | *errmsg = NULL; | |
701 | return dest; | |
702 | } | |
703 | ||
704 | static void | |
705 | print_bc (info, insn, value) | |
706 | disassemble_info *info; | |
707 | TXVU_INSN insn; | |
708 | long value; | |
709 | { | |
710 | char c; | |
711 | ||
712 | switch (value) | |
713 | { | |
714 | case TXVU_BC_X : c = 'x' ; break; | |
715 | case TXVU_BC_Y : c = 'y' ; break; | |
716 | case TXVU_BC_Z : c = 'z' ; break; | |
717 | case TXVU_BC_W : c = 'w' ; break; | |
718 | } | |
719 | ||
720 | (*info->fprintf_func) (info->stream, "%c", c); | |
721 | } | |
722 | \f | |
723 | /* FT register in broadcast case. */ | |
724 | ||
725 | static long | |
0b988d39 | 726 | parse_bcftreg (pstr, errmsg) |
3f897263 DE |
727 | char **pstr; |
728 | const char **errmsg; | |
729 | { | |
730 | char *str = *pstr; | |
731 | char *start; | |
732 | long reg; | |
733 | int reg_bc; | |
734 | ||
735 | if (tolower (str[0]) != 'v' | |
736 | || tolower (str[1]) != 'f') | |
737 | { | |
738 | *errmsg = "unknown register"; | |
739 | return 0; | |
740 | } | |
741 | ||
742 | /* FIXME: quick hack until the framework works. */ | |
743 | start = str = str + 2; | |
744 | while (*str && isdigit (*str)) | |
745 | ++str; | |
746 | reg = atoi (start); | |
747 | reg_bc = parse_bc (&str, errmsg); | |
748 | if (*errmsg) | |
749 | return 0; | |
750 | if (reg_bc != bc) | |
751 | { | |
752 | *errmsg = "register `bc' does not match instruction `bc'"; | |
753 | return 0; | |
754 | } | |
755 | *pstr = str; | |
756 | *errmsg = NULL; | |
757 | return reg; | |
758 | } | |
759 | ||
760 | static void | |
0b988d39 | 761 | print_bcftreg (info, insn, value) |
3f897263 DE |
762 | disassemble_info *info; |
763 | TXVU_INSN insn; | |
764 | long value; | |
765 | { | |
766 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
767 | print_bc (info, insn, bc); | |
768 | } | |
769 | \f | |
770 | /* ACC handling. */ | |
771 | ||
772 | static long | |
773 | parse_accdest (pstr, errmsg) | |
774 | char **pstr; | |
775 | const char **errmsg; | |
776 | { | |
777 | char *str = *pstr; | |
778 | long acc_dest = 0; | |
779 | ||
780 | if (strncasecmp (str, "acc", 3) != 0) | |
781 | { | |
782 | *errmsg = "expecting `acc'"; | |
783 | return 0; | |
784 | } | |
785 | str += 3; | |
786 | acc_dest = parse_dest (&str); | |
787 | if (acc_dest == 0 || isalnum (*str)) | |
788 | { | |
789 | *errmsg = "invalid `dest'"; | |
790 | return 0; | |
791 | } | |
792 | if (acc_dest != dest) | |
793 | { | |
794 | *errmsg = "acc `dest' does not match instruction `dest'"; | |
795 | return 0; | |
796 | } | |
797 | *pstr = str; | |
798 | *errmsg = NULL; | |
799 | /* Value isn't used, but we must return something. */ | |
800 | return 0; | |
801 | } | |
802 | ||
803 | static void | |
804 | print_accdest (info, insn, value) | |
805 | disassemble_info *info; | |
806 | TXVU_INSN insn; | |
807 | long value; | |
808 | { | |
809 | (*info->fprintf_func) (info->stream, "acc"); | |
810 | print_dest (info, insn, value); | |
811 | } | |
812 | \f | |
813 | /* XYZ operand handling. | |
814 | This simplifies the opmula,opmsub entries by keeping them equivalent to | |
815 | the others. */ | |
816 | ||
817 | static long | |
818 | parse_xyz (pstr, errmsg) | |
819 | char **pstr; | |
820 | const char **errmsg; | |
821 | { | |
822 | if (dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z)) | |
823 | { | |
824 | *errmsg = "expecting `xyz' for `dest' value"; | |
825 | return 0; | |
826 | } | |
827 | return 0; | |
828 | } | |
0b988d39 DE |
829 | \f |
830 | /* F[ST] register using selector in F[ST]F field. */ | |
831 | ||
832 | static long | |
833 | parse_ffstreg (pstr, errmsg) | |
834 | char **pstr; | |
835 | const char **errmsg; | |
836 | { | |
837 | char *str = *pstr; | |
838 | char *start; | |
839 | long reg; | |
840 | int reg_bc; | |
841 | ||
842 | if (tolower (str[0]) != 'v' | |
843 | || tolower (str[1]) != 'f') | |
844 | { | |
845 | *errmsg = "unknown register"; | |
846 | return 0; | |
847 | } | |
848 | ||
849 | /* FIXME: quick hack until the framework works. */ | |
850 | start = str = str + 2; | |
851 | while (*str && isdigit (*str)) | |
852 | ++str; | |
853 | reg = atoi (start); | |
854 | reg_bc = parse_bc (&str, errmsg); | |
855 | if (*errmsg) | |
856 | return 0; | |
857 | if (reg_bc != bc) | |
858 | { | |
859 | *errmsg = "register `bc' does not match instruction `bc'"; | |
860 | return 0; | |
861 | } | |
862 | *pstr = str; | |
863 | *errmsg = NULL; | |
864 | return reg; | |
865 | } | |
866 | ||
867 | static void | |
868 | print_ffstreg (info, insn, value) | |
869 | disassemble_info *info; | |
870 | TXVU_INSN insn; | |
871 | long value; | |
872 | { | |
873 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
874 | print_bc (info, insn, bc); | |
875 | } | |
876 | ||
877 | #define INSERT_FN(fn) \ | |
878 | static TXVU_INSN CONCAT2 (insert_,fn) \ | |
879 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
880 | int, long, const char **)) | |
881 | #define EXTRACT_FN(fn) \ | |
882 | static long CONCAT2 (extract_,fn) \ | |
883 | PARAMS ((TXVU_INSN, const struct txvu_operand *, \ | |
884 | int, int *)) | |
885 | ||
886 | static TXVU_INSN | |
887 | insert_ffstreg (insn, operand, mods, value, errmsg) | |
888 | TXVU_INSN insn; | |
889 | const struct txvu_operand *operand; | |
890 | int mods; | |
891 | long value; | |
892 | const char **errmsg; | |
893 | { | |
894 | } | |
895 | ||
896 | static long | |
897 | extract_ffstreg (insn, operand, mods, pinvalid) | |
898 | TXVU_INSN insn; | |
899 | const struct txvu_operand *operand; | |
900 | int mods; | |
901 | int *pinvalid; | |
902 | { | |
903 | } | |
904 | \f | |
905 | /* F register. */ | |
906 | ||
907 | static long | |
908 | parse_freg (pstr, errmsg) | |
909 | char **pstr; | |
910 | const char **errmsg; | |
911 | { | |
912 | char *str = *pstr; | |
913 | char *start; | |
914 | long reg; | |
915 | int reg_bc; | |
916 | ||
917 | if (tolower (str[0]) != 'v' | |
918 | || tolower (str[1]) != 'f') | |
919 | { | |
920 | *errmsg = "unknown register"; | |
921 | return 0; | |
922 | } | |
923 | ||
924 | /* FIXME: quick hack until the framework works. */ | |
925 | start = str = str + 2; | |
926 | while (*str && isdigit (*str)) | |
927 | ++str; | |
928 | reg = atoi (start); | |
929 | reg_bc = parse_bc (&str, errmsg); | |
930 | if (*errmsg) | |
931 | return 0; | |
932 | if (reg_bc != bc) | |
933 | { | |
934 | *errmsg = "register `bc' does not match instruction `bc'"; | |
935 | return 0; | |
936 | } | |
937 | *pstr = str; | |
938 | *errmsg = NULL; | |
939 | return reg; | |
940 | } | |
941 | ||
942 | static void | |
943 | print_freg (info, insn, value) | |
944 | disassemble_info *info; | |
945 | TXVU_INSN insn; | |
946 | long value; | |
947 | { | |
948 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
949 | print_bc (info, insn, bc); | |
950 | } | |
951 | \f | |
952 | /* I register. */ | |
953 | ||
954 | static long | |
955 | parse_ireg (pstr, errmsg) | |
956 | char **pstr; | |
957 | const char **errmsg; | |
958 | { | |
959 | char *str = *pstr; | |
960 | char *start; | |
961 | long reg; | |
962 | int reg_bc; | |
963 | ||
964 | if (tolower (str[0]) != 'v' | |
965 | || tolower (str[1]) != 'f') | |
966 | { | |
967 | *errmsg = "unknown register"; | |
968 | return 0; | |
969 | } | |
970 | ||
971 | /* FIXME: quick hack until the framework works. */ | |
972 | start = str = str + 2; | |
973 | while (*str && isdigit (*str)) | |
974 | ++str; | |
975 | reg = atoi (start); | |
976 | reg_bc = parse_bc (&str, errmsg); | |
977 | if (*errmsg) | |
978 | return 0; | |
979 | if (reg_bc != bc) | |
980 | { | |
981 | *errmsg = "register `bc' does not match instruction `bc'"; | |
982 | return 0; | |
983 | } | |
984 | *pstr = str; | |
985 | *errmsg = NULL; | |
986 | return reg; | |
987 | } | |
988 | ||
989 | static void | |
990 | print_ireg (info, insn, value) | |
991 | disassemble_info *info; | |
992 | TXVU_INSN insn; | |
993 | long value; | |
994 | { | |
995 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
996 | print_bc (info, insn, bc); | |
997 | } | |
998 | \f | |
999 | /* VI01 register. */ | |
1000 | ||
1001 | static long | |
1002 | parse_vi01 (pstr, errmsg) | |
1003 | char **pstr; | |
1004 | const char **errmsg; | |
1005 | { | |
1006 | char *str = *pstr; | |
1007 | char *start; | |
1008 | long reg; | |
1009 | int reg_bc; | |
1010 | ||
1011 | if (tolower (str[0]) != 'v' | |
1012 | || tolower (str[1]) != 'f') | |
1013 | { | |
1014 | *errmsg = "unknown register"; | |
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | /* FIXME: quick hack until the framework works. */ | |
1019 | start = str = str + 2; | |
1020 | while (*str && isdigit (*str)) | |
1021 | ++str; | |
1022 | reg = atoi (start); | |
1023 | reg_bc = parse_bc (&str, errmsg); | |
1024 | if (*errmsg) | |
1025 | return 0; | |
1026 | if (reg_bc != bc) | |
1027 | { | |
1028 | *errmsg = "register `bc' does not match instruction `bc'"; | |
1029 | return 0; | |
1030 | } | |
1031 | *pstr = str; | |
1032 | *errmsg = NULL; | |
1033 | return reg; | |
1034 | } | |
1035 | ||
1036 | static void | |
1037 | print_vi01 (info, insn, value) | |
1038 | disassemble_info *info; | |
1039 | TXVU_INSN insn; | |
1040 | long value; | |
1041 | { | |
1042 | (*info->fprintf_func) (info->stream, "vf%ld", value); | |
1043 | print_bc (info, insn, bc); | |
1044 | } | |
1045 | \f | |
1046 | /* Lower instruction 12 bit immediate. */ | |
1047 | ||
1048 | static TXVU_INSN | |
1049 | insert_limm12 (insn, operand, mods, value, errmsg) | |
1050 | TXVU_INSN insn; | |
1051 | const struct txvu_operand *operand; | |
1052 | int mods; | |
1053 | long value; | |
1054 | const char **errmsg; | |
1055 | { | |
1056 | } | |
1057 | ||
1058 | static long | |
1059 | extract_limm12 (insn, operand, mods, pinvalid) | |
1060 | TXVU_INSN insn; | |
1061 | const struct txvu_operand *operand; | |
1062 | int mods; | |
1063 | int *pinvalid; | |
1064 | { | |
1065 | } |