1*d2201f2fSdrahn /* mmix-dis.c -- Disassemble MMIX instructions.
2*d2201f2fSdrahn Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
3*d2201f2fSdrahn Written by Hans-Peter Nilsson (hp@bitrange.com)
4*d2201f2fSdrahn
5*d2201f2fSdrahn This file is part of GDB and the GNU binutils.
6*d2201f2fSdrahn
7*d2201f2fSdrahn GDB and the GNU binutils are free software; you can redistribute
8*d2201f2fSdrahn them and/or modify them under the terms of the GNU General Public
9*d2201f2fSdrahn License as published by the Free Software Foundation; either version 2,
10*d2201f2fSdrahn or (at your option) any later version.
11*d2201f2fSdrahn
12*d2201f2fSdrahn GDB and the GNU binutils are distributed in the hope that they
13*d2201f2fSdrahn will be useful, but WITHOUT ANY WARRANTY; without even the implied
14*d2201f2fSdrahn warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15*d2201f2fSdrahn the GNU General Public License for more details.
16*d2201f2fSdrahn
17*d2201f2fSdrahn You should have received a copy of the GNU General Public License
18*d2201f2fSdrahn along with this file; see the file COPYING. If not, write to the Free
19*d2201f2fSdrahn Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20*d2201f2fSdrahn
21*d2201f2fSdrahn #include <stdio.h>
22*d2201f2fSdrahn #include <string.h>
23*d2201f2fSdrahn #include <stdlib.h>
24*d2201f2fSdrahn #include "opcode/mmix.h"
25*d2201f2fSdrahn #include "dis-asm.h"
26*d2201f2fSdrahn #include "libiberty.h"
27*d2201f2fSdrahn #include "bfd.h"
28*d2201f2fSdrahn #include "opintl.h"
29*d2201f2fSdrahn
30*d2201f2fSdrahn #define BAD_CASE(x) \
31*d2201f2fSdrahn do \
32*d2201f2fSdrahn { \
33*d2201f2fSdrahn fprintf (stderr, \
34*d2201f2fSdrahn _("Bad case %d (%s) in %s:%d\n"), \
35*d2201f2fSdrahn x, #x, __FILE__, __LINE__); \
36*d2201f2fSdrahn abort (); \
37*d2201f2fSdrahn } \
38*d2201f2fSdrahn while (0)
39*d2201f2fSdrahn
40*d2201f2fSdrahn #define FATAL_DEBUG \
41*d2201f2fSdrahn do \
42*d2201f2fSdrahn { \
43*d2201f2fSdrahn fprintf (stderr, \
44*d2201f2fSdrahn _("Internal: Non-debugged code (test-case missing): %s:%d"), \
45*d2201f2fSdrahn __FILE__, __LINE__); \
46*d2201f2fSdrahn abort (); \
47*d2201f2fSdrahn } \
48*d2201f2fSdrahn while (0)
49*d2201f2fSdrahn
50*d2201f2fSdrahn #define ROUND_MODE(n) \
51*d2201f2fSdrahn ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \
52*d2201f2fSdrahn (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \
53*d2201f2fSdrahn _("(unknown)"))
54*d2201f2fSdrahn
55*d2201f2fSdrahn #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
56*d2201f2fSdrahn #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
57*d2201f2fSdrahn
58*d2201f2fSdrahn struct mmix_dis_info
59*d2201f2fSdrahn {
60*d2201f2fSdrahn const char *reg_name[256];
61*d2201f2fSdrahn const char *spec_reg_name[32];
62*d2201f2fSdrahn
63*d2201f2fSdrahn /* Waste a little memory so we don't have to allocate each separately.
64*d2201f2fSdrahn We could have an array with static contents for these, but on the
65*d2201f2fSdrahn other hand, we don't have to. */
66*d2201f2fSdrahn char basic_reg_name[256][sizeof ("$255")];
67*d2201f2fSdrahn };
68*d2201f2fSdrahn
69*d2201f2fSdrahn static bfd_boolean initialize_mmix_dis_info
70*d2201f2fSdrahn PARAMS ((struct disassemble_info *));
71*d2201f2fSdrahn static const struct mmix_opcode *get_opcode
72*d2201f2fSdrahn PARAMS ((unsigned long));
73*d2201f2fSdrahn
74*d2201f2fSdrahn
75*d2201f2fSdrahn /* Initialize a target-specific array in INFO. */
76*d2201f2fSdrahn
77*d2201f2fSdrahn static bfd_boolean
initialize_mmix_dis_info(info)78*d2201f2fSdrahn initialize_mmix_dis_info (info)
79*d2201f2fSdrahn struct disassemble_info *info;
80*d2201f2fSdrahn {
81*d2201f2fSdrahn struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
82*d2201f2fSdrahn int i;
83*d2201f2fSdrahn
84*d2201f2fSdrahn if (minfop == NULL)
85*d2201f2fSdrahn return FALSE;
86*d2201f2fSdrahn
87*d2201f2fSdrahn memset (minfop, 0, sizeof (*minfop));
88*d2201f2fSdrahn
89*d2201f2fSdrahn /* Initialize register names from register symbols. If there's no
90*d2201f2fSdrahn register section, then there are no register symbols. */
91*d2201f2fSdrahn if ((info->section != NULL && info->section->owner != NULL)
92*d2201f2fSdrahn || (info->symbols != NULL
93*d2201f2fSdrahn && info->symbols[0] != NULL
94*d2201f2fSdrahn && bfd_asymbol_bfd (info->symbols[0]) != NULL))
95*d2201f2fSdrahn {
96*d2201f2fSdrahn bfd *abfd = info->section && info->section->owner != NULL
97*d2201f2fSdrahn ? info->section->owner
98*d2201f2fSdrahn : bfd_asymbol_bfd (info->symbols[0]);
99*d2201f2fSdrahn asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
100*d2201f2fSdrahn
101*d2201f2fSdrahn if (reg_section != NULL)
102*d2201f2fSdrahn {
103*d2201f2fSdrahn /* The returned symcount *does* include the ending NULL. */
104*d2201f2fSdrahn long symsize = bfd_get_symtab_upper_bound (abfd);
105*d2201f2fSdrahn asymbol **syms = malloc (symsize);
106*d2201f2fSdrahn long nsyms;
107*d2201f2fSdrahn long i;
108*d2201f2fSdrahn
109*d2201f2fSdrahn if (syms == NULL)
110*d2201f2fSdrahn { FATAL_DEBUG;
111*d2201f2fSdrahn free (minfop);
112*d2201f2fSdrahn return FALSE;
113*d2201f2fSdrahn }
114*d2201f2fSdrahn nsyms = bfd_canonicalize_symtab (abfd, syms);
115*d2201f2fSdrahn
116*d2201f2fSdrahn /* We use the first name for a register. If this is MMO, then
117*d2201f2fSdrahn it's the name with the first sequence number, presumably the
118*d2201f2fSdrahn first in the source. */
119*d2201f2fSdrahn for (i = 0; i < nsyms && syms[i] != NULL; i++)
120*d2201f2fSdrahn {
121*d2201f2fSdrahn if (syms[i]->section == reg_section
122*d2201f2fSdrahn && syms[i]->value < 256
123*d2201f2fSdrahn && minfop->reg_name[syms[i]->value] == NULL)
124*d2201f2fSdrahn minfop->reg_name[syms[i]->value] = syms[i]->name;
125*d2201f2fSdrahn }
126*d2201f2fSdrahn }
127*d2201f2fSdrahn }
128*d2201f2fSdrahn
129*d2201f2fSdrahn /* Fill in the rest with the canonical names. */
130*d2201f2fSdrahn for (i = 0; i < 256; i++)
131*d2201f2fSdrahn if (minfop->reg_name[i] == NULL)
132*d2201f2fSdrahn {
133*d2201f2fSdrahn sprintf (minfop->basic_reg_name[i], "$%d", i);
134*d2201f2fSdrahn minfop->reg_name[i] = minfop->basic_reg_name[i];
135*d2201f2fSdrahn }
136*d2201f2fSdrahn
137*d2201f2fSdrahn /* We assume it's actually a one-to-one mapping of number-to-name. */
138*d2201f2fSdrahn for (i = 0; mmix_spec_regs[i].name != NULL; i++)
139*d2201f2fSdrahn minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
140*d2201f2fSdrahn
141*d2201f2fSdrahn info->private_data = (PTR) minfop;
142*d2201f2fSdrahn return TRUE;
143*d2201f2fSdrahn }
144*d2201f2fSdrahn
145*d2201f2fSdrahn /* A table indexed by the first byte is constructed as we disassemble each
146*d2201f2fSdrahn tetrabyte. The contents is a pointer into mmix_insns reflecting the
147*d2201f2fSdrahn first found entry with matching match-bits and lose-bits. Further
148*d2201f2fSdrahn entries are considered one after one until the operand constraints
149*d2201f2fSdrahn match or the match-bits and lose-bits do not match. Normally a
150*d2201f2fSdrahn "further entry" will just show that there was no other match. */
151*d2201f2fSdrahn
152*d2201f2fSdrahn static const struct mmix_opcode *
get_opcode(insn)153*d2201f2fSdrahn get_opcode (insn)
154*d2201f2fSdrahn unsigned long insn;
155*d2201f2fSdrahn {
156*d2201f2fSdrahn static const struct mmix_opcode **opcodes = NULL;
157*d2201f2fSdrahn const struct mmix_opcode *opcodep = mmix_opcodes;
158*d2201f2fSdrahn unsigned int opcode_part = (insn >> 24) & 255;
159*d2201f2fSdrahn if (opcodes == NULL)
160*d2201f2fSdrahn opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
161*d2201f2fSdrahn
162*d2201f2fSdrahn opcodep = opcodes[opcode_part];
163*d2201f2fSdrahn if (opcodep == NULL
164*d2201f2fSdrahn || (opcodep->match & insn) != opcodep->match
165*d2201f2fSdrahn || (opcodep->lose & insn) != 0)
166*d2201f2fSdrahn {
167*d2201f2fSdrahn /* Search through the table. */
168*d2201f2fSdrahn for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
169*d2201f2fSdrahn {
170*d2201f2fSdrahn /* FIXME: Break out this into an initialization function. */
171*d2201f2fSdrahn if ((opcodep->match & (opcode_part << 24)) == opcode_part
172*d2201f2fSdrahn && (opcodep->lose & (opcode_part << 24)) == 0)
173*d2201f2fSdrahn opcodes[opcode_part] = opcodep;
174*d2201f2fSdrahn
175*d2201f2fSdrahn if ((opcodep->match & insn) == opcodep->match
176*d2201f2fSdrahn && (opcodep->lose & insn) == 0)
177*d2201f2fSdrahn break;
178*d2201f2fSdrahn }
179*d2201f2fSdrahn }
180*d2201f2fSdrahn
181*d2201f2fSdrahn if (opcodep->name == NULL)
182*d2201f2fSdrahn return NULL;
183*d2201f2fSdrahn
184*d2201f2fSdrahn /* Check constraints. If they don't match, loop through the next opcode
185*d2201f2fSdrahn entries. */
186*d2201f2fSdrahn do
187*d2201f2fSdrahn {
188*d2201f2fSdrahn switch (opcodep->operands)
189*d2201f2fSdrahn {
190*d2201f2fSdrahn /* These have no restraint on what can be in the lower three
191*d2201f2fSdrahn bytes. */
192*d2201f2fSdrahn case mmix_operands_regs:
193*d2201f2fSdrahn case mmix_operands_reg_yz:
194*d2201f2fSdrahn case mmix_operands_regs_z_opt:
195*d2201f2fSdrahn case mmix_operands_regs_z:
196*d2201f2fSdrahn case mmix_operands_jmp:
197*d2201f2fSdrahn case mmix_operands_pushgo:
198*d2201f2fSdrahn case mmix_operands_pop:
199*d2201f2fSdrahn case mmix_operands_sync:
200*d2201f2fSdrahn case mmix_operands_x_regs_z:
201*d2201f2fSdrahn case mmix_operands_neg:
202*d2201f2fSdrahn case mmix_operands_pushj:
203*d2201f2fSdrahn case mmix_operands_regaddr:
204*d2201f2fSdrahn case mmix_operands_get:
205*d2201f2fSdrahn case mmix_operands_set:
206*d2201f2fSdrahn case mmix_operands_save:
207*d2201f2fSdrahn case mmix_operands_unsave:
208*d2201f2fSdrahn case mmix_operands_xyz_opt:
209*d2201f2fSdrahn return opcodep;
210*d2201f2fSdrahn
211*d2201f2fSdrahn /* For a ROUND_MODE, the middle byte must be 0..4. */
212*d2201f2fSdrahn case mmix_operands_roundregs_z:
213*d2201f2fSdrahn case mmix_operands_roundregs:
214*d2201f2fSdrahn {
215*d2201f2fSdrahn int midbyte = (insn >> 8) & 255;
216*d2201f2fSdrahn if (midbyte <= 4)
217*d2201f2fSdrahn return opcodep;
218*d2201f2fSdrahn }
219*d2201f2fSdrahn break;
220*d2201f2fSdrahn
221*d2201f2fSdrahn case mmix_operands_put:
222*d2201f2fSdrahn /* A "PUT". If it is "immediate", then no restrictions,
223*d2201f2fSdrahn otherwise we have to make sure the register number is < 32. */
224*d2201f2fSdrahn if ((insn & INSN_IMMEDIATE_BIT)
225*d2201f2fSdrahn || ((insn >> 16) & 255) < 32)
226*d2201f2fSdrahn return opcodep;
227*d2201f2fSdrahn break;
228*d2201f2fSdrahn
229*d2201f2fSdrahn case mmix_operands_resume:
230*d2201f2fSdrahn /* Middle bytes must be zero. */
231*d2201f2fSdrahn if ((insn & 0x00ffff00) == 0)
232*d2201f2fSdrahn return opcodep;
233*d2201f2fSdrahn break;
234*d2201f2fSdrahn
235*d2201f2fSdrahn default:
236*d2201f2fSdrahn BAD_CASE (opcodep->operands);
237*d2201f2fSdrahn }
238*d2201f2fSdrahn
239*d2201f2fSdrahn opcodep++;
240*d2201f2fSdrahn }
241*d2201f2fSdrahn while ((opcodep->match & insn) == opcodep->match
242*d2201f2fSdrahn && (opcodep->lose & insn) == 0);
243*d2201f2fSdrahn
244*d2201f2fSdrahn /* If we got here, we had no match. */
245*d2201f2fSdrahn return NULL;
246*d2201f2fSdrahn }
247*d2201f2fSdrahn
248*d2201f2fSdrahn /* The main disassembly function. */
249*d2201f2fSdrahn
250*d2201f2fSdrahn int
print_insn_mmix(memaddr,info)251*d2201f2fSdrahn print_insn_mmix (memaddr, info)
252*d2201f2fSdrahn bfd_vma memaddr;
253*d2201f2fSdrahn struct disassemble_info *info;
254*d2201f2fSdrahn {
255*d2201f2fSdrahn unsigned char buffer[4];
256*d2201f2fSdrahn unsigned long insn;
257*d2201f2fSdrahn unsigned int x, y, z;
258*d2201f2fSdrahn const struct mmix_opcode *opcodep;
259*d2201f2fSdrahn int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
260*d2201f2fSdrahn struct mmix_dis_info *minfop;
261*d2201f2fSdrahn
262*d2201f2fSdrahn if (status != 0)
263*d2201f2fSdrahn {
264*d2201f2fSdrahn (*info->memory_error_func) (status, memaddr, info);
265*d2201f2fSdrahn return -1;
266*d2201f2fSdrahn }
267*d2201f2fSdrahn
268*d2201f2fSdrahn /* FIXME: Is -1 suitable? */
269*d2201f2fSdrahn if (info->private_data == NULL
270*d2201f2fSdrahn && ! initialize_mmix_dis_info (info))
271*d2201f2fSdrahn return -1;
272*d2201f2fSdrahn
273*d2201f2fSdrahn minfop = (struct mmix_dis_info *) info->private_data;
274*d2201f2fSdrahn x = buffer[1];
275*d2201f2fSdrahn y = buffer[2];
276*d2201f2fSdrahn z = buffer[3];
277*d2201f2fSdrahn
278*d2201f2fSdrahn insn = bfd_getb32 (buffer);
279*d2201f2fSdrahn
280*d2201f2fSdrahn opcodep = get_opcode (insn);
281*d2201f2fSdrahn
282*d2201f2fSdrahn if (opcodep == NULL)
283*d2201f2fSdrahn {
284*d2201f2fSdrahn (*info->fprintf_func) (info->stream, _("*unknown*"));
285*d2201f2fSdrahn return 4;
286*d2201f2fSdrahn }
287*d2201f2fSdrahn
288*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
289*d2201f2fSdrahn
290*d2201f2fSdrahn /* Present bytes in the order they are laid out in memory. */
291*d2201f2fSdrahn info->display_endian = BFD_ENDIAN_BIG;
292*d2201f2fSdrahn
293*d2201f2fSdrahn info->insn_info_valid = 1;
294*d2201f2fSdrahn info->bytes_per_chunk = 4;
295*d2201f2fSdrahn info->branch_delay_insns = 0;
296*d2201f2fSdrahn info->target = 0;
297*d2201f2fSdrahn switch (opcodep->type)
298*d2201f2fSdrahn {
299*d2201f2fSdrahn case mmix_type_normal:
300*d2201f2fSdrahn case mmix_type_memaccess_block:
301*d2201f2fSdrahn info->insn_type = dis_nonbranch;
302*d2201f2fSdrahn break;
303*d2201f2fSdrahn
304*d2201f2fSdrahn case mmix_type_branch:
305*d2201f2fSdrahn info->insn_type = dis_branch;
306*d2201f2fSdrahn break;
307*d2201f2fSdrahn
308*d2201f2fSdrahn case mmix_type_condbranch:
309*d2201f2fSdrahn info->insn_type = dis_condbranch;
310*d2201f2fSdrahn break;
311*d2201f2fSdrahn
312*d2201f2fSdrahn case mmix_type_memaccess_octa:
313*d2201f2fSdrahn info->insn_type = dis_dref;
314*d2201f2fSdrahn info->data_size = 8;
315*d2201f2fSdrahn break;
316*d2201f2fSdrahn
317*d2201f2fSdrahn case mmix_type_memaccess_tetra:
318*d2201f2fSdrahn info->insn_type = dis_dref;
319*d2201f2fSdrahn info->data_size = 4;
320*d2201f2fSdrahn break;
321*d2201f2fSdrahn
322*d2201f2fSdrahn case mmix_type_memaccess_wyde:
323*d2201f2fSdrahn info->insn_type = dis_dref;
324*d2201f2fSdrahn info->data_size = 2;
325*d2201f2fSdrahn break;
326*d2201f2fSdrahn
327*d2201f2fSdrahn case mmix_type_memaccess_byte:
328*d2201f2fSdrahn info->insn_type = dis_dref;
329*d2201f2fSdrahn info->data_size = 1;
330*d2201f2fSdrahn break;
331*d2201f2fSdrahn
332*d2201f2fSdrahn case mmix_type_jsr:
333*d2201f2fSdrahn info->insn_type = dis_jsr;
334*d2201f2fSdrahn break;
335*d2201f2fSdrahn
336*d2201f2fSdrahn default:
337*d2201f2fSdrahn BAD_CASE(opcodep->type);
338*d2201f2fSdrahn }
339*d2201f2fSdrahn
340*d2201f2fSdrahn switch (opcodep->operands)
341*d2201f2fSdrahn {
342*d2201f2fSdrahn case mmix_operands_regs:
343*d2201f2fSdrahn /* All registers: "$X,$Y,$Z". */
344*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%s",
345*d2201f2fSdrahn minfop->reg_name[x],
346*d2201f2fSdrahn minfop->reg_name[y],
347*d2201f2fSdrahn minfop->reg_name[z]);
348*d2201f2fSdrahn break;
349*d2201f2fSdrahn
350*d2201f2fSdrahn case mmix_operands_reg_yz:
351*d2201f2fSdrahn /* Like SETH - "$X,YZ". */
352*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,0x%x",
353*d2201f2fSdrahn minfop->reg_name[x], y * 256 + z);
354*d2201f2fSdrahn break;
355*d2201f2fSdrahn
356*d2201f2fSdrahn case mmix_operands_regs_z_opt:
357*d2201f2fSdrahn case mmix_operands_regs_z:
358*d2201f2fSdrahn case mmix_operands_pushgo:
359*d2201f2fSdrahn /* The regular "$X,$Y,$Z|Z". */
360*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
361*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%d",
362*d2201f2fSdrahn minfop->reg_name[x], minfop->reg_name[y], z);
363*d2201f2fSdrahn else
364*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%s",
365*d2201f2fSdrahn minfop->reg_name[x],
366*d2201f2fSdrahn minfop->reg_name[y],
367*d2201f2fSdrahn minfop->reg_name[z]);
368*d2201f2fSdrahn break;
369*d2201f2fSdrahn
370*d2201f2fSdrahn case mmix_operands_jmp:
371*d2201f2fSdrahn /* Address; only JMP. */
372*d2201f2fSdrahn {
373*d2201f2fSdrahn bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
374*d2201f2fSdrahn
375*d2201f2fSdrahn if (insn & INSN_BACKWARD_OFFSET_BIT)
376*d2201f2fSdrahn offset -= (256 * 65536) * 4;
377*d2201f2fSdrahn
378*d2201f2fSdrahn info->target = memaddr + offset;
379*d2201f2fSdrahn (*info->print_address_func) (memaddr + offset, info);
380*d2201f2fSdrahn }
381*d2201f2fSdrahn break;
382*d2201f2fSdrahn
383*d2201f2fSdrahn case mmix_operands_roundregs_z:
384*d2201f2fSdrahn /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
385*d2201f2fSdrahn "$X,ROUND_MODE,$Z|Z". */
386*d2201f2fSdrahn if (y != 0)
387*d2201f2fSdrahn {
388*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
389*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%d",
390*d2201f2fSdrahn minfop->reg_name[x],
391*d2201f2fSdrahn ROUND_MODE (y), z);
392*d2201f2fSdrahn else
393*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%s",
394*d2201f2fSdrahn minfop->reg_name[x],
395*d2201f2fSdrahn ROUND_MODE (y),
396*d2201f2fSdrahn minfop->reg_name[z]);
397*d2201f2fSdrahn }
398*d2201f2fSdrahn else
399*d2201f2fSdrahn {
400*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
401*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%d",
402*d2201f2fSdrahn minfop->reg_name[x], z);
403*d2201f2fSdrahn else
404*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s",
405*d2201f2fSdrahn minfop->reg_name[x],
406*d2201f2fSdrahn minfop->reg_name[z]);
407*d2201f2fSdrahn }
408*d2201f2fSdrahn break;
409*d2201f2fSdrahn
410*d2201f2fSdrahn case mmix_operands_pop:
411*d2201f2fSdrahn /* Like POP - "X,YZ". */
412*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
413*d2201f2fSdrahn break;
414*d2201f2fSdrahn
415*d2201f2fSdrahn case mmix_operands_roundregs:
416*d2201f2fSdrahn /* Two registers, possibly with rounding: "$X,$Z" or
417*d2201f2fSdrahn "$X,ROUND_MODE,$Z". */
418*d2201f2fSdrahn if (y != 0)
419*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s,%s",
420*d2201f2fSdrahn minfop->reg_name[x],
421*d2201f2fSdrahn ROUND_MODE (y),
422*d2201f2fSdrahn minfop->reg_name[z]);
423*d2201f2fSdrahn else
424*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s",
425*d2201f2fSdrahn minfop->reg_name[x],
426*d2201f2fSdrahn minfop->reg_name[z]);
427*d2201f2fSdrahn break;
428*d2201f2fSdrahn
429*d2201f2fSdrahn case mmix_operands_sync:
430*d2201f2fSdrahn /* Like SYNC - "XYZ". */
431*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%u",
432*d2201f2fSdrahn x * 65536 + y * 256 + z);
433*d2201f2fSdrahn break;
434*d2201f2fSdrahn
435*d2201f2fSdrahn case mmix_operands_x_regs_z:
436*d2201f2fSdrahn /* Like SYNCD - "X,$Y,$Z|Z". */
437*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
438*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%d,%s,%d",
439*d2201f2fSdrahn x, minfop->reg_name[y], z);
440*d2201f2fSdrahn else
441*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%d,%s,%s",
442*d2201f2fSdrahn x, minfop->reg_name[y],
443*d2201f2fSdrahn minfop->reg_name[z]);
444*d2201f2fSdrahn break;
445*d2201f2fSdrahn
446*d2201f2fSdrahn case mmix_operands_neg:
447*d2201f2fSdrahn /* Like NEG and NEGU - "$X,Y,$Z|Z". */
448*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
449*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%d,%d",
450*d2201f2fSdrahn minfop->reg_name[x], y, z);
451*d2201f2fSdrahn else
452*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%d,%s",
453*d2201f2fSdrahn minfop->reg_name[x], y,
454*d2201f2fSdrahn minfop->reg_name[z]);
455*d2201f2fSdrahn break;
456*d2201f2fSdrahn
457*d2201f2fSdrahn case mmix_operands_pushj:
458*d2201f2fSdrahn case mmix_operands_regaddr:
459*d2201f2fSdrahn /* Like GETA or branches - "$X,Address". */
460*d2201f2fSdrahn {
461*d2201f2fSdrahn bfd_signed_vma offset = (y * 256 + z) * 4;
462*d2201f2fSdrahn
463*d2201f2fSdrahn if (insn & INSN_BACKWARD_OFFSET_BIT)
464*d2201f2fSdrahn offset -= 65536 * 4;
465*d2201f2fSdrahn
466*d2201f2fSdrahn info->target = memaddr + offset;
467*d2201f2fSdrahn
468*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
469*d2201f2fSdrahn (*info->print_address_func) (memaddr + offset, info);
470*d2201f2fSdrahn }
471*d2201f2fSdrahn break;
472*d2201f2fSdrahn
473*d2201f2fSdrahn case mmix_operands_get:
474*d2201f2fSdrahn /* GET - "X,spec_reg". */
475*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s",
476*d2201f2fSdrahn minfop->reg_name[x],
477*d2201f2fSdrahn minfop->spec_reg_name[z]);
478*d2201f2fSdrahn break;
479*d2201f2fSdrahn
480*d2201f2fSdrahn case mmix_operands_put:
481*d2201f2fSdrahn /* PUT - "spec_reg,$Z|Z". */
482*d2201f2fSdrahn if (insn & INSN_IMMEDIATE_BIT)
483*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%d",
484*d2201f2fSdrahn minfop->spec_reg_name[x], z);
485*d2201f2fSdrahn else
486*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s",
487*d2201f2fSdrahn minfop->spec_reg_name[x],
488*d2201f2fSdrahn minfop->reg_name[z]);
489*d2201f2fSdrahn break;
490*d2201f2fSdrahn
491*d2201f2fSdrahn case mmix_operands_set:
492*d2201f2fSdrahn /* Two registers, "$X,$Y". */
493*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,%s",
494*d2201f2fSdrahn minfop->reg_name[x],
495*d2201f2fSdrahn minfop->reg_name[y]);
496*d2201f2fSdrahn break;
497*d2201f2fSdrahn
498*d2201f2fSdrahn case mmix_operands_save:
499*d2201f2fSdrahn /* SAVE - "$X,0". */
500*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
501*d2201f2fSdrahn break;
502*d2201f2fSdrahn
503*d2201f2fSdrahn case mmix_operands_unsave:
504*d2201f2fSdrahn /* UNSAVE - "0,$Z". */
505*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
506*d2201f2fSdrahn break;
507*d2201f2fSdrahn
508*d2201f2fSdrahn case mmix_operands_xyz_opt:
509*d2201f2fSdrahn /* Like SWYM or TRAP - "X,Y,Z". */
510*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
511*d2201f2fSdrahn break;
512*d2201f2fSdrahn
513*d2201f2fSdrahn case mmix_operands_resume:
514*d2201f2fSdrahn /* Just "Z", like RESUME. */
515*d2201f2fSdrahn (*info->fprintf_func) (info->stream, "%d", z);
516*d2201f2fSdrahn break;
517*d2201f2fSdrahn
518*d2201f2fSdrahn default:
519*d2201f2fSdrahn (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
520*d2201f2fSdrahn opcodep->operands);
521*d2201f2fSdrahn break;
522*d2201f2fSdrahn }
523*d2201f2fSdrahn
524*d2201f2fSdrahn return 4;
525*d2201f2fSdrahn }
526