* txvu-opc.c (txvu_operands, UBC): Add extract entry.
[deliverable/binutils-gdb.git] / opcodes / txvu-opc.c
CommitLineData
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) \
38static long CONCAT2 (parse_,fn) \
39 PARAMS ((char **, const char **));
40#define INSERT_FN(fn) \
41static TXVU_INSN CONCAT2 (insert_,fn) \
42 PARAMS ((TXVU_INSN, const struct txvu_operand *, \
43 int, long, const char **))
44#define EXTRACT_FN(fn) \
45static long CONCAT2 (extract_,fn) \
46 PARAMS ((TXVU_INSN, const struct txvu_operand *, \
47 int, int *))
48#define PRINT_FN(fn) \
49static void CONCAT2 (print_,fn) \
50 PARAMS ((disassemble_info *, TXVU_INSN, long));
51
52PARSE_FN (dotdest);
71af45ec
DE
53INSERT_FN (dotdest);
54EXTRACT_FN (dotdest);
54cc8ed4
DE
55PRINT_FN (dotdest);
56
eb7168e5
DE
57PARSE_FN (dotdest1);
58
59PARSE_FN (bc);
d1128f73 60EXTRACT_FN (bc);
eb7168e5 61PRINT_FN (sdest);
8ea2f96f 62
71af45ec
DE
63PARSE_FN (vfreg);
64PRINT_FN (vfreg);
54cc8ed4 65
0b988d39
DE
66PARSE_FN (bcftreg);
67PRINT_FN (bcftreg);
3f897263
DE
68
69PARSE_FN (accdest);
70PRINT_FN (accdest);
71
d1128f73 72INSERT_FN (xyz);
3f897263 73
0b988d39
DE
74PARSE_FN (ireg);
75PRINT_FN (ireg);
76
77PARSE_FN (freg);
78PRINT_FN (freg);
79
80PARSE_FN (ffstreg);
81INSERT_FN (ffstreg);
82EXTRACT_FN (ffstreg);
83PRINT_FN (ffstreg);
84
85PARSE_FN (vi01);
86PRINT_FN (vi01);
87
eb7168e5
DE
88INSERT_FN (luimm12);
89EXTRACT_FN (luimm12);
0b988d39 90
8ea2f96f
DE
91INSERT_FN (luimm15);
92EXTRACT_FN (luimm15);
93
3f897263 94/* Various types of TXVU operands, including insn suffixes.
54cc8ed4
DE
95
96 Fields are:
97
98 BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
99
100 Operand values are 128 + table index. This allows ASCII chars to be
101 included in the syntax spec. */
102
103const struct txvu_operand txvu_operands[] =
104{
3f897263 105 /* place holder (??? not sure if needed) */
54cc8ed4
DE
106#define UNUSED 128
107 { 0 },
108
8ea2f96f 109 /* Operands that exist in the same place for essentially the same purpose
eb7168e5
DE
110 in both upper and lower instructions. These don't have a U or L prefix.
111 Operands specific to the upper or lower instruction are so prefixed. */
0b988d39 112
8ea2f96f
DE
113 /* Destination indicator attached to mnemonic, with leading '.'.
114 After parsing this, the value is stored in global `dest' so that the
115 register parser can verify the same choice of xyzw is used. */
116#define DOTDEST (UNUSED + 1)
54cc8ed4 117 { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
71af45ec 118 parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest },
54cc8ed4 119
8ea2f96f
DE
120 /* ft reg, with vector specification same as DOTDEST */
121#define VFTREG (DOTDEST + 1)
122 { 5, TXVU_SHIFT_TREG, 0, parse_vfreg, 0, 0, print_vfreg },
54cc8ed4 123
8ea2f96f
DE
124 /* fs reg, with vector specification same as DOTDEST */
125#define VFSREG (VFTREG + 1)
126 { 5, TXVU_SHIFT_SREG, 0, parse_vfreg, 0, 0, print_vfreg },
54cc8ed4 127
8ea2f96f
DE
128 /* fd reg, with vector specification same as DOTDEST */
129#define VFDREG (VFSREG + 1)
130 { 5, TXVU_SHIFT_DREG, 0, parse_vfreg, 0, 0, print_vfreg },
131
132 /* Upper word operands. */
54cc8ed4 133
3f897263 134 /* broadcast */
8ea2f96f 135#define UBC (VFDREG + 1)
d1128f73 136 { 2, 0, TXVU_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest },
3f897263
DE
137
138 /* ftreg in broadcast case */
0b988d39 139#define UBCFTREG (UBC + 1)
8ea2f96f 140 { 5, TXVU_SHIFT_TREG, 0, parse_bcftreg, 0, 0, print_bcftreg },
3f897263
DE
141
142 /* accumulator dest */
0b988d39 143#define UACCDEST (UBCFTREG + 1)
d1128f73 144 { 0, 0, 0, parse_accdest, 0, 0, print_accdest },
3f897263
DE
145
146 /* The XYZ operand is a fake one that is used to ensure only "xyz" is
147 specified. It simplifies the opmula and opmsub entries. */
0b988d39 148#define UXYZ (UACCDEST + 1)
d1128f73 149 { 0, 0, TXVU_OPERAND_FAKE, 0, insert_xyz, 0, 0 },
3f897263 150
0b988d39
DE
151 /* Lower word operands. */
152
97a6824d 153 /* 5 bit signed immediate. */
8ea2f96f 154#define LIMM5 (UXYZ + 1)
97a6824d 155 { 5, 6, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
8ea2f96f 156
97a6824d 157 /* 11 bit signed immediate. */
8ea2f96f 158#define LIMM11 (LIMM5 + 1)
97a6824d 159 { 11, 0, TXVU_OPERAND_SIGNED, 0, 0, 0, 0 },
0b988d39 160
8ea2f96f
DE
161 /* 15 bit unsigned immediate. */
162#define LUIMM15 (LIMM11 + 1)
97a6824d 163 { 15, 0, 0, 0, insert_luimm15, extract_luimm15, 0 },
8ea2f96f
DE
164
165 /* ID register. */
166#define LIDREG (LUIMM15 + 1)
167 { 5, 6, 0, parse_ireg, 0, 0, print_ireg },
168
0b988d39 169 /* IS register. */
8ea2f96f 170#define LISREG (LIDREG + 1)
0b988d39
DE
171 { 5, 11, 0, parse_ireg, 0, 0, print_ireg },
172
173 /* IT register. */
174#define LITREG (LISREG + 1)
175 { 5, 16, 0, parse_ireg, 0, 0, print_ireg },
176
177 /* FS reg, with FSF field selector. */
178#define LFSFFSREG (LITREG + 1)
179 { 5, 11, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
180
181 /* FS reg, no selector (choice of x,y,z,w is provided by opcode). */
182#define LFSREG (LFSFFSREG + 1)
183 { 5, 11, 0, parse_freg, 0, 0, print_freg },
184
185 /* FT reg, with FTF field selector. */
186#define LFTFFTREG (LFSREG + 1)
187 { 5, 16, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
188
189 /* VI01 register. */
190#define LVI01 (LFTFFTREG + 1)
d1128f73 191 { 0, 0, 0, parse_vi01, 0, 0, print_vi01 },
0b988d39 192
97a6824d
DE
193 /* 24 bit unsigned immediate. */
194#define LUIMM24 (LVI01 + 1)
0b988d39
DE
195 { 24, 0, 0, 0, 0, 0, 0 },
196
eb7168e5 197 /* 12 bit unsigned immediate, split into 1 and 11 bit pieces. */
97a6824d 198#define LUIMM12 (LUIMM24 + 1)
eb7168e5 199 { 12, 0, 0, 0, insert_luimm12, extract_luimm12, 0 },
0b988d39 200
1a702a24 201 /* 11 bit pc-relative signed immediate. */
eb7168e5 202#define LPCREL11 (LUIMM12 + 1)
1a702a24 203 { 11, 0, TXVU_OPERAND_SIGNED + TXVU_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 },
8ea2f96f 204
eb7168e5
DE
205 /* Destination indicator, single letter only, with leading '.'. */
206#define LDOTDEST1 (LPCREL11 + 1)
8ea2f96f
DE
207 { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
208 /* Note that we borrow the insert/extract/print functions from the
209 vector case. */
eb7168e5 210 parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
8ea2f96f 211
54cc8ed4
DE
212/* end of list place holder */
213 { 0 }
214};
215\f
216/* Macros to put a field's value into the right place. */
1a702a24 217/* ??? If assembler needs these, move to opcode/txvu.h. */
3f897263 218
0b988d39 219/* value X, B bits, shift S */
1a702a24 220#define V(x,b,s) (((x) & ((1 << (b)) - 1)) << (s))
0b988d39 221
8ea2f96f
DE
222/* Field value macros for both upper and lower instructions.
223 These shift a value into the right place in the instruction. */
224
225/* [FI] T reg field (remember it's V for value, not vector, here). */
1a702a24 226#define VT(x) V ((x), 5, TXVU_SHIFT_TREG)
8ea2f96f 227/* [FI] S reg field. */
1a702a24 228#define VS(x) V ((x), 5, TXVU_SHIFT_SREG)
8ea2f96f 229/* [FI] D reg field. */
1a702a24 230#define VD(x) V ((x), 5, TXVU_SHIFT_DREG)
8ea2f96f 231/* DEST field. */
1a702a24 232#define VDEST(x) V ((x), 4, 21)
8ea2f96f
DE
233
234/* Masks for fields in both upper and lower instructions.
235 These mask out all bits but the ones for the field in the instruction. */
236
237#define MT VT (~0)
238#define MS VS (~0)
239#define MD VD (~0)
240#define MDEST VDEST (~0)
241
0b988d39 242/* Upper instruction Value macros. */
54cc8ed4 243
3f897263 244/* Upper Flag bits. */
1a702a24 245#define VUF(x) V ((x), 5, 27)
3f897263 246/* Upper REServed two bits next to flag bits. */
1a702a24 247#define VURES(x) V ((x), 2, 25)
0b988d39 248/* 4 bit opcode field. */
1a702a24 249#define VUOP4(x) V ((x), 4, 2)
0b988d39 250/* 6 bit opcode field. */
1a702a24 251#define VUOP6(x) V ((x), 6, 0)
0b988d39 252/* 9 bit opcode field. */
1a702a24 253#define VUOP9(x) V ((x), 9, 2)
0b988d39 254/* 11 bit opcode field. */
1a702a24 255#define VUOP11(x) V ((x), 11, 0)
0b988d39 256/* BroadCast field. */
1a702a24 257#define VUBC(x) V ((x), 2, 0)
0b988d39 258
8ea2f96f 259/* Upper instruction field masks. */
0b988d39
DE
260#define MUUBITS (VUF (~0) + VURES (~0))
261#define MURES VURES (~0)
262#define MUOP4 VUOP4 (~0)
263#define MUOP6 VUOP6 (~0)
264#define MUOP9 VUOP9 (~0)
265#define MUOP11 VUOP11 (~0)
266
1a702a24
DE
267/* A space, separates instruction name (mnemonic + mnemonic operands) from
268 operands. */
3f897263 269#define SP ' '
1a702a24
DE
270/* Commas separate operands. */
271#define C ','
272/* Special I,P,Q,R operands. */
273#define I 'i'
274#define P 'p'
275#define Q 'q'
276#define R 'r'
3f897263 277
54cc8ed4
DE
278/* TXVU instructions.
279 [??? some of these comments are left over from the ARC port from which
280 this code is borrowed, delete in time]
281
282 Longer versions of insns must appear before shorter ones (if gas sees
283 "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
284 junk). This isn't necessary for `ld' because of the trailing ']'.
285
286 Instructions that are really macros based on other insns must appear
287 before the real insn so they're chosen when disassembling. Eg: The `mov'
288 insn is really the `and' insn.
289
290 This table is best viewed on a wide screen (161 columns). I'd prefer to
291 keep it this way. The rest of the file, however, should be viewable on an
292 80 column terminal. */
293
294/* ??? This table also includes macros: asl, lsl, and mov. The ppc port has
295 a more general facility for dealing with macros which could be used if
296 we need to. */
297
298/* These tables can't be `const' because members `next_asm' and `next_dis' are
299 computed at run-time. We could split this into two, as that would put the
300 constant stuff into a readonly section. */
301
302struct txvu_opcode txvu_upper_opcodes[] = {
303
1a702a24 304 /* Macros appear first, so the disassembler will try them first. */
54cc8ed4 305 /* ??? Any aliases? */
1a702a24 306 /* ??? When close to being finished, clean up by aligning fields. */
54cc8ed4 307
3f897263 308 /* The rest of these needn't be sorted, but it helps to find them if they are. */
1a702a24
DE
309 { "abs", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x1fd) },
310 { "add", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x28) },
311 { "addi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x22) },
312 { "addq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x20) },
313 { "add", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (0) },
314 { "adda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bc) },
315 { "addai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23e) },
316 { "addaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23c) },
317 { "adda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0xf) },
8ea2f96f 318 { "clip", { DOTDEST, SP, VFSREG }, MURES + MDEST + MT + MUOP11, VDEST (0xf) + VUOP11 (0x1ff) },
1a702a24
DE
319 { "ftoi0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17c) },
320 { "ftoi4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17d) },
321 { "ftoi12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17e) },
322 { "ftoi15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x17f) },
323 { "itof0", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13c) },
324 { "itof4", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13d) },
325 { "itof12", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13e) },
326 { "itof15", { DOTDEST, SP, VFTREG, C, VFSREG }, MURES + MUOP11, VUOP11 (0x13f) },
327 { "madd", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x29) },
328 { "maddi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x23) },
329 { "maddq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x21) },
330 { "madd", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x2) },
331 { "madda", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2bd) },
332 { "maddai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x23f) },
333 { "maddaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x23d) },
334 { "madda", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x2f) },
335 { "max", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2b) },
336 { "maxi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x2d) },
337 { "max", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x4) },
338 /* ??? mini or min? */
339 { "mini", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2f) },
d1128f73 340 { "minii", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1f) },
1a702a24
DE
341 { "mini", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x5) },
342 { "msub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2d) },
343 { "msubi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x27) },
344 { "msubq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x25) },
345 { "msub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4, VUOP4 (0x3) },
346 { "msuba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fd) },
347 { "msubai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27f) },
348 { "msubaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27d) },
349 { "msuba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x3f) },
350 { "mul", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2a) },
351 { "muli", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x1e) },
352 { "mulq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x1c) },
353 { "mul", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (6) },
354 { "mula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2be) },
355 { "mulai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x1fe) },
356 { "mulaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x1fc) },
357 { "mula", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x6f) },
8ea2f96f 358 { "nop", { 0 }, MURES + MDEST + MT + MS + MUOP11, VUOP11 (0x2ff) },
1a702a24
DE
359 { "opmula", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP11, VUOP11 (0x2fe) },
360 { "opmsub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP6, VUOP6 (0x2e) },
361 { "sub", { DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG }, MURES + MUOP6, VUOP6 (0x2c) },
362 { "subi", { DOTDEST, SP, VFDREG, C, VFSREG, C, I }, MURES + MT + MUOP6, VUOP6 (0x26) },
363 { "subq", { DOTDEST, SP, VFDREG, C, VFSREG, C, Q }, MURES + MT + MUOP6, VUOP6 (0x24) },
364 { "sub", { UBC, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0), VUOP4 (1) },
365 { "suba", { DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG }, MURES + MUOP11, VUOP11 (0x2fc) },
366 { "subai", { DOTDEST, SP, UACCDEST, C, VFSREG, C, I }, MURES + MT + MUOP11, VUOP11 (0x27e) },
367 { "subaq", { DOTDEST, SP, UACCDEST, C, VFSREG, C, Q }, MURES + MT + MUOP11, VUOP11 (0x27c) },
368 { "suba", { UBC, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9, VUOP9 (0x1f) }
54cc8ed4 369};
97a6824d 370const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_upper_opcodes[0]);
8ea2f96f
DE
371\f
372/* Lower instruction Value macros. */
373
374/* 6 bit opcode. */
1a702a24 375#define VLOP6(x) V ((x), 6, 0)
8ea2f96f 376/* 7 bit opcode. */
1a702a24 377#define VLOP7(x) V ((x), 7, 25)
8ea2f96f 378/* 11 bit opcode. */
1a702a24 379#define VLOP11(x) V ((x), 11, 0)
8ea2f96f 380/* 11 bit immediate. */
1a702a24 381#define VLIMM11(x) V ((x), 11, 0)
8ea2f96f 382/* FTF field. */
1a702a24 383#define VLFTF(x) V ((x), 2, 23)
8ea2f96f 384/* FSF field. */
1a702a24 385#define VLFSF(x) V ((x), 2, 21)
eb7168e5 386/* Upper bit of 12 bit unsigned immediate. */
1a702a24 387#define VLUIMM12TOP(x) V ((x), 1, 21)
eb7168e5
DE
388/* Upper 4 bits of 15 bit unsigned immediate. */
389#define VLUIMM15TOP(x) VDEST (x)
8ea2f96f
DE
390
391/* Lower instruction field masks. */
392#define MLOP6 VLOP6 (~0)
393#define MLOP7 VLOP7 (~0)
394#define MLOP11 VLOP11 (~0)
395#define MLIMM11 VLIMM11 (~0)
1a702a24 396#define MLB24 V (1, 1, 24)
eb7168e5
DE
397#define MLUIMM12TOP VLUIMM12TOP (~0)
398/* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits.
8ea2f96f
DE
399 The upper 1 bit is part of the `dest' field. This mask is for the
400 other 3 bits of the dest field. */
1a702a24 401#define MLUIMM12UNUSED V (7, 3, 22)
eb7168e5 402#define MLUIMM15TOP MDEST
54cc8ed4
DE
403
404struct txvu_opcode txvu_lower_opcodes[] = {
405
1a702a24 406 /* Macros appear first, so the disassembler will try them first. */
54cc8ed4 407 /* ??? Any aliases? */
1a702a24
DE
408 /* ??? There isn't an explicit nop. Apparently it's "move vf0,vf0". */
409 { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) },
54cc8ed4 410
0b988d39 411 /* The rest of these needn't be sorted, but it helps to find them if they are. */
8ea2f96f 412 { "b", { SP, LPCREL11 }, MLOP7 + MDEST + MT + MS, VLOP7 (0x20) },
1a702a24
DE
413 { "bal", { SP, LITREG, C, LPCREL11 }, MLOP7 + MDEST + MS, VLOP7 (0x21) },
414 { "div", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLOP11, VLOP7 (0x40) + VLOP11 (0x3bc) },
415 { "eatan", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) },
416 { "eatanxy", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77c) },
417 { "eatanxz", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77d) },
418 { "eexp", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) },
419 { "eleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x74e) },
420 { "ercpr", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) },
421 { "erleng", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73f) },
422 { "ersadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73d) },
423 { "ersqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) },
424 { "esadd", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x73c) },
425 { "esin", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) },
426 { "esqrt", { SP, P, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) },
427 { "esum", { SP, P, C, LFSREG }, MLOP7 + MDEST + MT + MLOP11, VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) },
428 { "fcand", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x12) },
429 { "fceq", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) },
8ea2f96f 430 { "fcget", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x1c) },
1a702a24
DE
431 { "fcor", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) },
432 { "fcset", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) },
433 { "fmand", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1a) },
434 { "fmeq", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x18) },
435 { "fmor", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1b) },
436 { "fsand", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x16) },
437 { "fseq", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x14) },
438 { "fsor", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x17) },
439 { "fsset", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x15) },
440 { "iadd", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x30) },
441 { "iaddi", { SP, LITREG, C, LISREG, C, LIMM5 }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x32) },
442 { "iaddiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x08) },
443 { "iand", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
444 { "ibeq", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x28) },
445 { "ibgez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2f) },
446 { "iblez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2e) },
447 { "ibltz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2c) },
448 { "ibne", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x29) },
8ea2f96f 449 /* FIXME: Need to not require commas around parens. */
1a702a24
DE
450 { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x04) },
451 { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3fe) },
452 { "ior", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
453 { "isub", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x31) },
454 { "isubiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x09) },
455 { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x05) },
456 { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3ff) },
457 { "jalr", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x25) },
8ea2f96f 458 { "jr", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x24) },
1a702a24 459 { "lq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x00) },
8ea2f96f 460 /* FIXME: No commas around -/+. */
1a702a24
DE
461 { "lqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37e) },
462 { "lqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37c) },
eb7168e5 463 /* Only a single VF reg is allowed here. We can use VFTREG because LDOTDEST1
8ea2f96f 464 handles verifying only a single choice of xyzw is present. */
1a702a24
DE
465 { "mfir", { LDOTDEST1, SP, VFTREG, C, LISREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fc) },
466 { "mfp", { DOTDEST, SP, VFTREG, C, P }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x67c) },
467 { "move", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33c) },
468 { "mr32", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33d) },
469 { "mtir", { LDOTDEST1, SP, LITREG, C, LFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) },
470 { "rget", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43d) },
471 { "rinit", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) },
472 { "rnext", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43c) },
473 { "rsqrt", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3be) },
474 { "rxor", { R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
475 { "sq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x01) },
8ea2f96f 476 /* FIXME: No commas around -/+. */
1a702a24
DE
477 { "sqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37f) },
478 { "sqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37d) },
479 { "sqrt", { SP, Q, C, LFTFFTREG }, MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) },
8ea2f96f
DE
480 { "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) },
481 { "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) },
482 { "xgkick", { LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) },
483 { "xitop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) },
484 { "xtop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) }
54cc8ed4 485};
97a6824d 486const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]);
8ea2f96f 487\f
54cc8ed4
DE
488/* Indexed by first letter of opcode. Points to chain of opcodes with same
489 first letter. */
490/* ??? One can certainly use a better hash. Later. */
491static struct txvu_opcode *upper_opcode_map[26 + 1];
492static struct txvu_opcode *lower_opcode_map[26 + 1];
493
494/* Indexed by insn code. Points to chain of opcodes with same insn code. */
1a702a24
DE
495static struct txvu_opcode *upper_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
496static struct txvu_opcode *lower_icode_map[(1 << TXVU_ICODE_HASH_SIZE) - 1];
54cc8ed4
DE
497\f
498/* Initialize any tables that need it.
499 Must be called once at start up (or when first needed).
500
501 FLAGS is currently unused but is intended to control initialization. */
502
503void
504txvu_opcode_init_tables (flags)
505 int flags;
506{
507 static int init_p = 0;
508
509 /* We may be intentionally called more than once (for example gdb will call
510 us each time the user switches cpu). These tables only need to be init'd
511 once though. */
512 /* ??? We can remove the need for txvu_opcode_supported by taking it into
513 account here, but I'm not sure I want to do that yet (if ever). */
514 if (!init_p)
515 {
516 int i,n;
517
518 memset (upper_opcode_map, 0, sizeof (upper_opcode_map));
519 memset (upper_icode_map, 0, sizeof (upper_icode_map));
520
521 /* Scan the table backwards so macros appear at the front. */
522 for (i = txvu_upper_opcodes_count - 1; i >= 0; --i)
523 {
524 int opcode_hash = TXVU_HASH_UPPER_OPCODE (txvu_upper_opcodes[i].mnemonic);
525 int icode_hash = TXVU_HASH_UPPER_ICODE (txvu_upper_opcodes[i].value);
526
527 txvu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash];
528 upper_opcode_map[opcode_hash] = &txvu_upper_opcodes[i];
529
530 txvu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash];
531 upper_icode_map[icode_hash] = &txvu_upper_opcodes[i];
532 }
533
534 memset (lower_opcode_map, 0, sizeof (lower_opcode_map));
535 memset (lower_icode_map, 0, sizeof (lower_icode_map));
536
537 /* Scan the table backwards so macros appear at the front. */
538 for (i = txvu_lower_opcodes_count - 1; i >= 0; --i)
539 {
540 int opcode_hash = TXVU_HASH_LOWER_OPCODE (txvu_lower_opcodes[i].mnemonic);
541 int icode_hash = TXVU_HASH_LOWER_ICODE (txvu_lower_opcodes[i].value);
542
543 txvu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash];
544 lower_opcode_map[opcode_hash] = &txvu_lower_opcodes[i];
545
546 txvu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash];
547 lower_icode_map[icode_hash] = &txvu_lower_opcodes[i];
548 }
549
550 init_p = 1;
551 }
552}
553
554/* Return the first insn in the chain for assembling upper INSN. */
555
556const struct txvu_opcode *
557txvu_upper_opcode_lookup_asm (insn)
558 const char *insn;
559{
560 return upper_opcode_map[TXVU_HASH_UPPER_OPCODE (insn)];
561}
562
563/* Return the first insn in the chain for assembling lower INSN. */
564
565const struct txvu_opcode *
566txvu_lower_opcode_lookup_asm (insn)
567 const char *insn;
568{
569 return lower_opcode_map[TXVU_HASH_LOWER_OPCODE (insn)];
570}
571
572/* Return the first insn in the chain for disassembling upper INSN. */
573
574const struct txvu_opcode *
575txvu_upper_opcode_lookup_dis (insn)
576 TXVU_INSN insn;
577{
578 return upper_icode_map[TXVU_HASH_UPPER_ICODE (insn)];
579}
580
581/* Return the first insn in the chain for disassembling lower INSN. */
582
583const struct txvu_opcode *
584txvu_lower_opcode_lookup_dis (insn)
585 TXVU_INSN insn;
586{
587 return lower_icode_map[TXVU_HASH_LOWER_ICODE (insn)];
588}
589\f
590/* Value of DEST in use.
71af45ec 591 Each of the registers must specify the same value as the opcode.
54cc8ed4
DE
592 ??? Perhaps remove the duplication? */
593static int dest;
3f897263
DE
594
595/* Value of BC to use.
596 The register specified for the ftreg must match the broadcast register
597 specified in the opcode. */
598static int bc;
54cc8ed4
DE
599\f
600/* Init fns.
601 These are called before doing each of the respective activities. */
602
603/* Called by the assembler before parsing an instruction. */
604
605void
606txvu_opcode_init_parse ()
607{
608 dest = -1;
3f897263 609 bc = -1;
54cc8ed4
DE
610}
611
612/* Called by the disassembler before printing an instruction. */
613
614void
615txvu_opcode_init_print ()
616{
617 dest = -1;
3f897263 618 bc = -1;
54cc8ed4
DE
619}
620\f
8ea2f96f 621/* Multiple destination choice support.
54cc8ed4
DE
622 The "dest" string selects any combination of x,y,z,w.
623 [The letters are ordered that way to follow the manual's style.] */
624
eb7168e5 625/* Utility to parse a `dest' spec.
71af45ec
DE
626 Return the found value.
627 *PSTR is set to the character that terminated the parsing.
628 It is up to the caller to do any error checking. */
629
54cc8ed4 630static long
eb7168e5 631_parse_dest (pstr)
54cc8ed4 632 char **pstr;
54cc8ed4
DE
633{
634 long dest = 0;
635
54cc8ed4
DE
636 while (**pstr)
637 {
638 switch (**pstr)
639 {
640 case 'x' : case 'X' : dest |= TXVU_DEST_X; break;
641 case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break;
642 case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break;
643 case 'w' : case 'W' : dest |= TXVU_DEST_W; break;
71af45ec 644 default : return dest;
54cc8ed4
DE
645 }
646 ++*pstr;
647 }
648
71af45ec
DE
649 return dest;
650}
651
652static long
653parse_dotdest (pstr, errmsg)
654 char **pstr;
655 const char **errmsg;
656{
657 long dest;
658
659 if (**pstr != '.')
660 {
661 *errmsg = "missing `.'";
662 return 0;
663 }
664
665 ++*pstr;
eb7168e5 666 dest = _parse_dest (pstr);
71af45ec
DE
667 if (dest == 0 || isalnum (**pstr))
668 {
669 *errmsg = "invalid `dest'";
670 return 0;
671 }
eb7168e5 672
54cc8ed4
DE
673 *errmsg = NULL;
674 return dest;
675}
676
eb7168e5
DE
677/* Parse a `dest' spec where only a single letter is allowed,
678 but the encoding handles all four. */
8ea2f96f
DE
679
680static long
eb7168e5 681parse_dotdest1 (pstr, errmsg)
8ea2f96f
DE
682 char **pstr;
683 const char **errmsg;
684{
eb7168e5 685 char c;
8ea2f96f
DE
686 long dest;
687
688 if (**pstr != '.')
689 {
690 *errmsg = "missing `.'";
691 return 0;
692 }
693
694 ++*pstr;
695 switch (**pstr)
696 {
eb7168e5
DE
697 case 'x' : case 'X' : dest |= TXVU_DEST_X; break;
698 case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break;
699 case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break;
700 case 'w' : case 'W' : dest |= TXVU_DEST_W; break;
8ea2f96f
DE
701 default : *errmsg = "invalid `dest'"; return 0;
702 }
eb7168e5
DE
703 ++*pstr;
704 c == tolower (**pstr);
705 if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
706 {
707 *errmsg = "only one of x,y,z,w can be specified";
708 return 0;
709 }
710 if (isalnum (**pstr))
711 {
712 *errmsg = "invalid `dest'";
713 return 0;
714 }
715
8ea2f96f
DE
716 *errmsg = NULL;
717 return dest;
718}
719
71af45ec
DE
720static TXVU_INSN
721insert_dotdest (insn, operand, mods, value, errmsg)
722 TXVU_INSN insn;
723 const struct txvu_operand *operand;
724 int mods;
725 long value;
726 const char **errmsg;
727{
728 /* Record the DEST value in use so the register parser can use it. */
729 dest = value;
730 if (errmsg)
731 *errmsg = NULL;
732 return insn |= value << operand->shift;
733}
734
735static long
736extract_dotdest (insn, operand, mods, pinvalid)
737 TXVU_INSN insn;
738 const struct txvu_operand *operand;
739 int mods;
740 int *pinvalid;
741{
742 /* Record the DEST value in use so the register printer can use it. */
743 dest = (insn >> operand->shift) & ((1 << operand->bits) - 1);
744 return dest;
745}
746
eb7168e5
DE
747/* Utility to print a multiple dest spec. */
748
54cc8ed4 749static void
eb7168e5 750_print_dest (info, insn, value)
54cc8ed4
DE
751 disassemble_info *info;
752 TXVU_INSN insn;
753 long value;
754{
54cc8ed4
DE
755 if (value & TXVU_DEST_X)
756 (*info->fprintf_func) (info->stream, "x");
757 if (value & TXVU_DEST_Y)
758 (*info->fprintf_func) (info->stream, "y");
759 if (value & TXVU_DEST_Z)
760 (*info->fprintf_func) (info->stream, "z");
761 if (value & TXVU_DEST_W)
762 (*info->fprintf_func) (info->stream, "w");
763}
71af45ec
DE
764
765static void
766print_dotdest (info, insn, value)
767 disassemble_info *info;
768 TXVU_INSN insn;
769 long value;
770{
771 (*info->fprintf_func) (info->stream, ".");
eb7168e5
DE
772 _print_dest (info, insn, value);
773}
774\f
775/* Utilities for single destination choice handling. */
776
777static long
778_parse_sdest (pstr, errmsg)
779 char **pstr;
780 const char **errmsg;
781{
782 char c;
783 long dest = 0;
784
785 switch (**pstr)
786 {
787 case 'x' : case 'X' : dest = TXVU_SDEST_X; break;
788 case 'y' : case 'Y' : dest = TXVU_SDEST_Y; break;
789 case 'z' : case 'Z' : dest = TXVU_SDEST_Z; break;
790 case 'w' : case 'W' : dest = TXVU_SDEST_W; break;
791 default : *errmsg = "only one of x,y,z,w can be specified"; return 0;
792 }
793 ++*pstr;
794 c == tolower (**pstr);
795 if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
796 {
797 *errmsg = "only one of x,y,z,w can be specified";
798 return 0;
799 }
800 if (isalnum (**pstr))
801 {
802 *errmsg = "invalid `dest'";
803 return 0;
804 }
805
806 *errmsg = NULL;
807 return dest;
808}
809
810static void
811print_sdest (info, insn, value)
812 disassemble_info *info;
813 TXVU_INSN insn;
814 long value;
815{
816 char c;
817
818 switch (value)
819 {
820 case TXVU_SDEST_X : c = 'x'; break;
821 case TXVU_SDEST_Y : c = 'y'; break;
822 case TXVU_SDEST_Z : c = 'z'; break;
823 case TXVU_SDEST_W : c = 'w'; break;
824 }
825
826 (*info->fprintf_func) (info->stream, "%c", c);
827}
828\f
829/* Broadcase field. */
830
831static long
832parse_bc (pstr, errmsg)
833 char **pstr;
834 const char **errmsg;
835{
836 long value = _parse_sdest (pstr, errmsg);
837
838 if (*errmsg)
839 return 0;
840 /* Save value for later verification in register parsing. */
841 bc = value;
842 return value;
843}
844
845/* During the extraction process, save the bc field for use in
846 printing the bc register. */
847
848static long
849extract_bc (insn, operand, mods, pinvalid)
850 TXVU_INSN insn;
851 const struct txvu_operand *operand;
852 int mods;
853 int *pinvalid;
854{
855 bc = insn & 3;
856 return bc;
71af45ec 857}
54cc8ed4
DE
858\f
859static long
71af45ec 860parse_vfreg (pstr, errmsg)
54cc8ed4
DE
861 char **pstr;
862 const char **errmsg;
863{
864 char *str = *pstr;
865 char *start;
866 long reg;
71af45ec 867 int reg_dest;
54cc8ed4
DE
868
869 if (tolower (str[0]) != 'v'
870 || tolower (str[1]) != 'f')
871 {
872 *errmsg = "unknown register";
873 return 0;
874 }
875
876 /* FIXME: quick hack until the framework works. */
877 start = str = str + 2;
878 while (*str && isdigit (*str))
879 ++str;
880 reg = atoi (start);
eb7168e5
DE
881 if (reg < 0 || reg > 31)
882 {
883 *errmsg = "invalid register number";
884 return 0;
885 }
886 reg_dest = _parse_dest (&str);
71af45ec
DE
887 if (reg_dest == 0 || isalnum (*str))
888 {
889 *errmsg = "invalid `dest'";
890 return 0;
891 }
892 if (reg_dest != dest)
893 {
894 *errmsg = "register `dest' does not match instruction `dest'";
895 return 0;
896 }
54cc8ed4
DE
897 *pstr = str;
898 *errmsg = NULL;
899 return reg;
900}
901
902static void
71af45ec 903print_vfreg (info, insn, value)
54cc8ed4
DE
904 disassemble_info *info;
905 TXVU_INSN insn;
906 long value;
907{
d1128f73 908 (*info->fprintf_func) (info->stream, "vf%02ld", value);
eb7168e5 909 _print_dest (info, insn, dest);
3f897263
DE
910}
911\f
912/* FT register in broadcast case. */
913
914static long
0b988d39 915parse_bcftreg (pstr, errmsg)
3f897263
DE
916 char **pstr;
917 const char **errmsg;
918{
919 char *str = *pstr;
920 char *start;
921 long reg;
922 int reg_bc;
923
924 if (tolower (str[0]) != 'v'
925 || tolower (str[1]) != 'f')
926 {
927 *errmsg = "unknown register";
928 return 0;
929 }
930
931 /* FIXME: quick hack until the framework works. */
932 start = str = str + 2;
933 while (*str && isdigit (*str))
934 ++str;
935 reg = atoi (start);
eb7168e5
DE
936 if (reg < 0 || reg > 31)
937 {
938 *errmsg = "invalid register number";
939 return 0;
940 }
941 reg_bc = _parse_sdest (&str, errmsg);
3f897263
DE
942 if (*errmsg)
943 return 0;
944 if (reg_bc != bc)
945 {
946 *errmsg = "register `bc' does not match instruction `bc'";
947 return 0;
948 }
949 *pstr = str;
950 *errmsg = NULL;
951 return reg;
952}
953
954static void
0b988d39 955print_bcftreg (info, insn, value)
3f897263
DE
956 disassemble_info *info;
957 TXVU_INSN insn;
958 long value;
959{
d1128f73 960 (*info->fprintf_func) (info->stream, "vf%02ld", value);
eb7168e5 961 print_sdest (info, insn, bc);
3f897263
DE
962}
963\f
964/* ACC handling. */
965
966static long
967parse_accdest (pstr, errmsg)
968 char **pstr;
969 const char **errmsg;
970{
971 char *str = *pstr;
972 long acc_dest = 0;
973
974 if (strncasecmp (str, "acc", 3) != 0)
975 {
976 *errmsg = "expecting `acc'";
977 return 0;
978 }
979 str += 3;
eb7168e5 980 acc_dest = _parse_dest (&str);
3f897263
DE
981 if (acc_dest == 0 || isalnum (*str))
982 {
983 *errmsg = "invalid `dest'";
984 return 0;
985 }
986 if (acc_dest != dest)
987 {
988 *errmsg = "acc `dest' does not match instruction `dest'";
989 return 0;
990 }
991 *pstr = str;
992 *errmsg = NULL;
993 /* Value isn't used, but we must return something. */
994 return 0;
995}
996
997static void
998print_accdest (info, insn, value)
999 disassemble_info *info;
1000 TXVU_INSN insn;
1001 long value;
1002{
1003 (*info->fprintf_func) (info->stream, "acc");
d1128f73 1004 _print_dest (info, insn, dest);
3f897263
DE
1005}
1006\f
1007/* XYZ operand handling.
1008 This simplifies the opmula,opmsub entries by keeping them equivalent to
1009 the others. */
1010
d1128f73
DE
1011static TXVU_INSN
1012insert_xyz (insn, operand, mods, value, errmsg)
1013 TXVU_INSN insn;
1014 const struct txvu_operand *operand;
1015 int mods;
1016 long value;
3f897263
DE
1017 const char **errmsg;
1018{
1019 if (dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
1020 {
1021 *errmsg = "expecting `xyz' for `dest' value";
d1128f73 1022 return insn;
3f897263 1023 }
d1128f73 1024 return insn;
3f897263 1025}
0b988d39 1026\f
eb7168e5
DE
1027/* F[ST] register using selector in F[ST]F field.
1028 Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator
1029 followed by the 5 bit register number. */
0b988d39
DE
1030
1031static long
1032parse_ffstreg (pstr, errmsg)
1033 char **pstr;
1034 const char **errmsg;
1035{
1036 char *str = *pstr;
1037 char *start;
eb7168e5 1038 int reg, xyzw;
0b988d39
DE
1039
1040 if (tolower (str[0]) != 'v'
1041 || tolower (str[1]) != 'f')
1042 {
1043 *errmsg = "unknown register";
1044 return 0;
1045 }
1046
1047 /* FIXME: quick hack until the framework works. */
1048 start = str = str + 2;
1049 while (*str && isdigit (*str))
1050 ++str;
1051 reg = atoi (start);
eb7168e5 1052 if (reg < 0 || reg > 31)
0b988d39 1053 {
eb7168e5 1054 *errmsg = "invalid register number";
0b988d39
DE
1055 return 0;
1056 }
eb7168e5
DE
1057 xyzw = _parse_sdest (&str, errmsg);
1058 if (*errmsg)
1059 return 0;
0b988d39
DE
1060 *pstr = str;
1061 *errmsg = NULL;
eb7168e5 1062 return reg | (xyzw << 5);
0b988d39
DE
1063}
1064
1065static void
1066print_ffstreg (info, insn, value)
1067 disassemble_info *info;
1068 TXVU_INSN insn;
1069 long value;
1070{
eb7168e5
DE
1071 (*info->fprintf_func) (info->stream, "vf%ld", value & TXVU_MASK_REG);
1072 print_sdest (info, insn, (value >> 5) & 3);
0b988d39
DE
1073}
1074
0b988d39
DE
1075static TXVU_INSN
1076insert_ffstreg (insn, operand, mods, value, errmsg)
1077 TXVU_INSN insn;
1078 const struct txvu_operand *operand;
1079 int mods;
1080 long value;
1081 const char **errmsg;
1082{
eb7168e5
DE
1083 if (operand->shift == TXVU_SHIFT_SREG)
1084 return insn | VLFSF (value >> 5) | VS (value);
1085 else
1086 return insn | VLFTF (value >> 5) | VT (value);
0b988d39
DE
1087}
1088
1089static long
1090extract_ffstreg (insn, operand, mods, pinvalid)
1091 TXVU_INSN insn;
1092 const struct txvu_operand *operand;
1093 int mods;
1094 int *pinvalid;
1095{
eb7168e5
DE
1096 if (operand->shift == TXVU_SHIFT_SREG)
1097 return (((insn & VLFSF (~0)) >> 21) << 5) | VS (insn);
1098 else
1099 return (((insn & VLFTF (~0)) >> 21) << 5) | VT (insn);
0b988d39
DE
1100}
1101\f
1102/* F register. */
1103
1104static long
1105parse_freg (pstr, errmsg)
1106 char **pstr;
1107 const char **errmsg;
1108{
1109 char *str = *pstr;
1110 char *start;
1111 long reg;
1112 int reg_bc;
1113
1114 if (tolower (str[0]) != 'v'
1115 || tolower (str[1]) != 'f')
1116 {
1117 *errmsg = "unknown register";
1118 return 0;
1119 }
1120
1121 /* FIXME: quick hack until the framework works. */
1122 start = str = str + 2;
1123 while (*str && isdigit (*str))
1124 ++str;
1125 reg = atoi (start);
eb7168e5 1126 if (reg < 0 || reg > 31)
0b988d39 1127 {
eb7168e5 1128 *errmsg = "invalid register number";
0b988d39
DE
1129 return 0;
1130 }
1131 *pstr = str;
1132 *errmsg = NULL;
1133 return reg;
1134}
1135
1136static void
1137print_freg (info, insn, value)
1138 disassemble_info *info;
1139 TXVU_INSN insn;
1140 long value;
1141{
1142 (*info->fprintf_func) (info->stream, "vf%ld", value);
0b988d39
DE
1143}
1144\f
1145/* I register. */
1146
1147static long
1148parse_ireg (pstr, errmsg)
1149 char **pstr;
1150 const char **errmsg;
1151{
1152 char *str = *pstr;
1153 char *start;
1154 long reg;
1155 int reg_bc;
1156
1157 if (tolower (str[0]) != 'v'
eb7168e5 1158 || tolower (str[1]) != 'i')
0b988d39
DE
1159 {
1160 *errmsg = "unknown register";
1161 return 0;
1162 }
1163
1164 /* FIXME: quick hack until the framework works. */
1165 start = str = str + 2;
1166 while (*str && isdigit (*str))
1167 ++str;
1168 reg = atoi (start);
eb7168e5 1169 if (reg < 0 || reg > 31)
0b988d39 1170 {
eb7168e5 1171 *errmsg = "invalid register number";
0b988d39
DE
1172 return 0;
1173 }
1174 *pstr = str;
1175 *errmsg = NULL;
1176 return reg;
1177}
1178
1179static void
1180print_ireg (info, insn, value)
1181 disassemble_info *info;
1182 TXVU_INSN insn;
1183 long value;
1184{
eb7168e5 1185 (*info->fprintf_func) (info->stream, "vi%ld", value);
0b988d39
DE
1186}
1187\f
1188/* VI01 register. */
1189
1190static long
1191parse_vi01 (pstr, errmsg)
1192 char **pstr;
1193 const char **errmsg;
1194{
1195 char *str = *pstr;
1196 char *start;
1197 long reg;
1198 int reg_bc;
1199
1200 if (tolower (str[0]) != 'v'
eb7168e5 1201 || tolower (str[1]) != 'i')
0b988d39
DE
1202 {
1203 *errmsg = "unknown register";
1204 return 0;
1205 }
1206
1207 /* FIXME: quick hack until the framework works. */
1208 start = str = str + 2;
1209 while (*str && isdigit (*str))
1210 ++str;
1211 reg = atoi (start);
eb7168e5 1212 if (reg != 1)
0b988d39 1213 {
eb7168e5 1214 *errmsg = "vi01 required here";
0b988d39
DE
1215 return 0;
1216 }
1217 *pstr = str;
1218 *errmsg = NULL;
1219 return reg;
1220}
1221
1222static void
1223print_vi01 (info, insn, value)
1224 disassemble_info *info;
1225 TXVU_INSN insn;
1226 long value;
1227{
eb7168e5 1228 (*info->fprintf_func) (info->stream, "vi01");
0b988d39
DE
1229}
1230\f
eb7168e5 1231/* Lower instruction 12 bit unsigned immediate. */
0b988d39
DE
1232
1233static TXVU_INSN
eb7168e5 1234insert_luimm12 (insn, operand, mods, value, errmsg)
0b988d39
DE
1235 TXVU_INSN insn;
1236 const struct txvu_operand *operand;
1237 int mods;
1238 long value;
1239 const char **errmsg;
1240{
eb7168e5 1241 return insn | VLUIMM12TOP ((value & (1 << 11)) != 0) | VLIMM11 (value);
0b988d39
DE
1242}
1243
1244static long
eb7168e5 1245extract_luimm12 (insn, operand, mods, pinvalid)
0b988d39
DE
1246 TXVU_INSN insn;
1247 const struct txvu_operand *operand;
1248 int mods;
1249 int *pinvalid;
1250{
eb7168e5 1251 return (((insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (insn);
0b988d39 1252}
8ea2f96f
DE
1253\f
1254/* Lower instruction 15 bit unsigned immediate. */
1255
1256static TXVU_INSN
1257insert_luimm15 (insn, operand, mods, value, errmsg)
1258 TXVU_INSN insn;
1259 const struct txvu_operand *operand;
1260 int mods;
1261 long value;
1262 const char **errmsg;
1263{
eb7168e5 1264 return insn | VLUIMM15TOP (value >> 11) | VLIMM11 (value);
8ea2f96f
DE
1265}
1266
1267static long
1268extract_luimm15 (insn, operand, mods, pinvalid)
1269 TXVU_INSN insn;
1270 const struct txvu_operand *operand;
1271 int mods;
1272 int *pinvalid;
1273{
eb7168e5 1274 return (((insn & MLUIMM15TOP) >> 21) << 11) | VLIMM11 (insn);
8ea2f96f 1275}
This page took 0.0897 seconds and 4 git commands to generate.