1 /* mmix-dis.c -- Disassemble MMIX instructions.
2 Copyright 2000, 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
3 Written by Hans-Peter Nilsson (hp@bitrange.com)
5 This file is part of the GNU opcodes library.
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
25 #include "opcode/mmix.h"
27 #include "libiberty.h"
35 _("Bad case %d (%s) in %s:%d\n"), \
36 x, #x, __FILE__, __LINE__); \
45 _("Internal: Non-debugged code (test-case missing): %s:%d"),\
46 __FILE__, __LINE__); \
51 #define ROUND_MODE(n) \
52 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \
53 (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \
56 #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
57 #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
61 const char *reg_name[256];
62 const char *spec_reg_name[32];
64 /* Waste a little memory so we don't have to allocate each separately.
65 We could have an array with static contents for these, but on the
66 other hand, we don't have to. */
67 char basic_reg_name[256][sizeof ("$255")];
70 /* Initialize a target-specific array in INFO. */
73 initialize_mmix_dis_info (struct disassemble_info *info)
75 struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
81 memset (minfop, 0, sizeof (*minfop));
83 /* Initialize register names from register symbols. If there's no
84 register section, then there are no register symbols. */
85 if ((info->section != NULL && info->section->owner != NULL)
86 || (info->symbols != NULL
87 && info->symbols[0] != NULL
88 && bfd_asymbol_bfd (info->symbols[0]) != NULL))
90 bfd *abfd = info->section && info->section->owner != NULL
91 ? info->section->owner
92 : bfd_asymbol_bfd (info->symbols[0]);
93 asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
95 if (reg_section != NULL)
97 /* The returned symcount *does* include the ending NULL. */
98 long symsize = bfd_get_symtab_upper_bound (abfd);
99 asymbol **syms = malloc (symsize);
108 nsyms = bfd_canonicalize_symtab (abfd, syms);
110 /* We use the first name for a register. If this is MMO, then
111 it's the name with the first sequence number, presumably the
112 first in the source. */
113 for (i = 0; i < nsyms && syms[i] != NULL; i++)
115 if (syms[i]->section == reg_section
116 && syms[i]->value < 256
117 && minfop->reg_name[syms[i]->value] == NULL)
118 minfop->reg_name[syms[i]->value] = syms[i]->name;
123 /* Fill in the rest with the canonical names. */
124 for (i = 0; i < 256; i++)
125 if (minfop->reg_name[i] == NULL)
127 sprintf (minfop->basic_reg_name[i], "$%ld", i);
128 minfop->reg_name[i] = minfop->basic_reg_name[i];
131 /* We assume it's actually a one-to-one mapping of number-to-name. */
132 for (i = 0; mmix_spec_regs[i].name != NULL; i++)
133 minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
135 info->private_data = (void *) minfop;
139 /* A table indexed by the first byte is constructed as we disassemble each
140 tetrabyte. The contents is a pointer into mmix_insns reflecting the
141 first found entry with matching match-bits and lose-bits. Further
142 entries are considered one after one until the operand constraints
143 match or the match-bits and lose-bits do not match. Normally a
144 "further entry" will just show that there was no other match. */
146 static const struct mmix_opcode *
147 get_opcode (unsigned long insn)
149 static const struct mmix_opcode **opcodes = NULL;
150 const struct mmix_opcode *opcodep = mmix_opcodes;
151 unsigned int opcode_part = (insn >> 24) & 255;
154 opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
156 opcodep = opcodes[opcode_part];
158 || (opcodep->match & insn) != opcodep->match
159 || (opcodep->lose & insn) != 0)
161 /* Search through the table. */
162 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
164 /* FIXME: Break out this into an initialization function. */
165 if ((opcodep->match & (opcode_part << 24)) == opcode_part
166 && (opcodep->lose & (opcode_part << 24)) == 0)
167 opcodes[opcode_part] = opcodep;
169 if ((opcodep->match & insn) == opcodep->match
170 && (opcodep->lose & insn) == 0)
175 if (opcodep->name == NULL)
178 /* Check constraints. If they don't match, loop through the next opcode
182 switch (opcodep->operands)
184 /* These have no restraint on what can be in the lower three
186 case mmix_operands_regs:
187 case mmix_operands_reg_yz:
188 case mmix_operands_regs_z_opt:
189 case mmix_operands_regs_z:
190 case mmix_operands_jmp:
191 case mmix_operands_pushgo:
192 case mmix_operands_pop:
193 case mmix_operands_sync:
194 case mmix_operands_x_regs_z:
195 case mmix_operands_neg:
196 case mmix_operands_pushj:
197 case mmix_operands_regaddr:
198 case mmix_operands_get:
199 case mmix_operands_set:
200 case mmix_operands_save:
201 case mmix_operands_unsave:
202 case mmix_operands_xyz_opt:
205 /* For a ROUND_MODE, the middle byte must be 0..4. */
206 case mmix_operands_roundregs_z:
207 case mmix_operands_roundregs:
209 int midbyte = (insn >> 8) & 255;
216 case mmix_operands_put:
217 /* A "PUT". If it is "immediate", then no restrictions,
218 otherwise we have to make sure the register number is < 32. */
219 if ((insn & INSN_IMMEDIATE_BIT)
220 || ((insn >> 16) & 255) < 32)
224 case mmix_operands_resume:
225 /* Middle bytes must be zero. */
226 if ((insn & 0x00ffff00) == 0)
231 BAD_CASE (opcodep->operands);
236 while ((opcodep->match & insn) == opcodep->match
237 && (opcodep->lose & insn) == 0);
239 /* If we got here, we had no match. */
243 /* The main disassembly function. */
246 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
248 unsigned char buffer[4];
250 unsigned int x, y, z;
251 const struct mmix_opcode *opcodep;
252 int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
253 struct mmix_dis_info *minfop;
257 (*info->memory_error_func) (status, memaddr, info);
261 /* FIXME: Is -1 suitable? */
262 if (info->private_data == NULL
263 && ! initialize_mmix_dis_info (info))
266 minfop = (struct mmix_dis_info *) info->private_data;
271 insn = bfd_getb32 (buffer);
273 opcodep = get_opcode (insn);
277 (*info->fprintf_func) (info->stream, _("*unknown*"));
281 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
283 /* Present bytes in the order they are laid out in memory. */
284 info->display_endian = BFD_ENDIAN_BIG;
286 info->insn_info_valid = 1;
287 info->bytes_per_chunk = 4;
288 info->branch_delay_insns = 0;
290 switch (opcodep->type)
292 case mmix_type_normal:
293 case mmix_type_memaccess_block:
294 info->insn_type = dis_nonbranch;
297 case mmix_type_branch:
298 info->insn_type = dis_branch;
301 case mmix_type_condbranch:
302 info->insn_type = dis_condbranch;
305 case mmix_type_memaccess_octa:
306 info->insn_type = dis_dref;
310 case mmix_type_memaccess_tetra:
311 info->insn_type = dis_dref;
315 case mmix_type_memaccess_wyde:
316 info->insn_type = dis_dref;
320 case mmix_type_memaccess_byte:
321 info->insn_type = dis_dref;
326 info->insn_type = dis_jsr;
330 BAD_CASE(opcodep->type);
333 switch (opcodep->operands)
335 case mmix_operands_regs:
336 /* All registers: "$X,$Y,$Z". */
337 (*info->fprintf_func) (info->stream, "%s,%s,%s",
340 minfop->reg_name[z]);
343 case mmix_operands_reg_yz:
344 /* Like SETH - "$X,YZ". */
345 (*info->fprintf_func) (info->stream, "%s,0x%x",
346 minfop->reg_name[x], y * 256 + z);
349 case mmix_operands_regs_z_opt:
350 case mmix_operands_regs_z:
351 case mmix_operands_pushgo:
352 /* The regular "$X,$Y,$Z|Z". */
353 if (insn & INSN_IMMEDIATE_BIT)
354 (*info->fprintf_func) (info->stream, "%s,%s,%d",
355 minfop->reg_name[x], minfop->reg_name[y], z);
357 (*info->fprintf_func) (info->stream, "%s,%s,%s",
360 minfop->reg_name[z]);
363 case mmix_operands_jmp:
364 /* Address; only JMP. */
366 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
368 if (insn & INSN_BACKWARD_OFFSET_BIT)
369 offset -= (256 * 65536) * 4;
371 info->target = memaddr + offset;
372 (*info->print_address_func) (memaddr + offset, info);
376 case mmix_operands_roundregs_z:
377 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
378 "$X,ROUND_MODE,$Z|Z". */
381 if (insn & INSN_IMMEDIATE_BIT)
382 (*info->fprintf_func) (info->stream, "%s,%s,%d",
386 (*info->fprintf_func) (info->stream, "%s,%s,%s",
389 minfop->reg_name[z]);
393 if (insn & INSN_IMMEDIATE_BIT)
394 (*info->fprintf_func) (info->stream, "%s,%d",
395 minfop->reg_name[x], z);
397 (*info->fprintf_func) (info->stream, "%s,%s",
399 minfop->reg_name[z]);
403 case mmix_operands_pop:
404 /* Like POP - "X,YZ". */
405 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
408 case mmix_operands_roundregs:
409 /* Two registers, possibly with rounding: "$X,$Z" or
410 "$X,ROUND_MODE,$Z". */
412 (*info->fprintf_func) (info->stream, "%s,%s,%s",
415 minfop->reg_name[z]);
417 (*info->fprintf_func) (info->stream, "%s,%s",
419 minfop->reg_name[z]);
422 case mmix_operands_sync:
423 /* Like SYNC - "XYZ". */
424 (*info->fprintf_func) (info->stream, "%u",
425 x * 65536 + y * 256 + z);
428 case mmix_operands_x_regs_z:
429 /* Like SYNCD - "X,$Y,$Z|Z". */
430 if (insn & INSN_IMMEDIATE_BIT)
431 (*info->fprintf_func) (info->stream, "%d,%s,%d",
432 x, minfop->reg_name[y], z);
434 (*info->fprintf_func) (info->stream, "%d,%s,%s",
435 x, minfop->reg_name[y],
436 minfop->reg_name[z]);
439 case mmix_operands_neg:
440 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
441 if (insn & INSN_IMMEDIATE_BIT)
442 (*info->fprintf_func) (info->stream, "%s,%d,%d",
443 minfop->reg_name[x], y, z);
445 (*info->fprintf_func) (info->stream, "%s,%d,%s",
446 minfop->reg_name[x], y,
447 minfop->reg_name[z]);
450 case mmix_operands_pushj:
451 case mmix_operands_regaddr:
452 /* Like GETA or branches - "$X,Address". */
454 bfd_signed_vma offset = (y * 256 + z) * 4;
456 if (insn & INSN_BACKWARD_OFFSET_BIT)
459 info->target = memaddr + offset;
461 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
462 (*info->print_address_func) (memaddr + offset, info);
466 case mmix_operands_get:
467 /* GET - "X,spec_reg". */
468 (*info->fprintf_func) (info->stream, "%s,%s",
470 minfop->spec_reg_name[z]);
473 case mmix_operands_put:
474 /* PUT - "spec_reg,$Z|Z". */
475 if (insn & INSN_IMMEDIATE_BIT)
476 (*info->fprintf_func) (info->stream, "%s,%d",
477 minfop->spec_reg_name[x], z);
479 (*info->fprintf_func) (info->stream, "%s,%s",
480 minfop->spec_reg_name[x],
481 minfop->reg_name[z]);
484 case mmix_operands_set:
485 /* Two registers, "$X,$Y". */
486 (*info->fprintf_func) (info->stream, "%s,%s",
488 minfop->reg_name[y]);
491 case mmix_operands_save:
493 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
496 case mmix_operands_unsave:
497 /* UNSAVE - "0,$Z". */
498 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
501 case mmix_operands_xyz_opt:
502 /* Like SWYM or TRAP - "X,Y,Z". */
503 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
506 case mmix_operands_resume:
507 /* Just "Z", like RESUME. */
508 (*info->fprintf_func) (info->stream, "%d", z);
512 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),