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