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);
109 nsyms = bfd_canonicalize_symtab (abfd, syms);
111 /* We use the first name for a register. If this is MMO, then
112 it's the name with the first sequence number, presumably the
113 first in the source. */
114 for (i = 0; i < nsyms && syms[i] != NULL; i++)
116 if (syms[i]->section == reg_section
117 && syms[i]->value < 256
118 && minfop->reg_name[syms[i]->value] == NULL)
119 minfop->reg_name[syms[i]->value] = syms[i]->name;
124 /* Fill in the rest with the canonical names. */
125 for (i = 0; i < 256; i++)
126 if (minfop->reg_name[i] == NULL)
128 sprintf (minfop->basic_reg_name[i], "$%d", i);
129 minfop->reg_name[i] = minfop->basic_reg_name[i];
132 /* We assume it's actually a one-to-one mapping of number-to-name. */
133 for (i = 0; mmix_spec_regs[i].name != NULL; i++)
134 minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
136 info->private_data = (void *) minfop;
140 /* A table indexed by the first byte is constructed as we disassemble each
141 tetrabyte. The contents is a pointer into mmix_insns reflecting the
142 first found entry with matching match-bits and lose-bits. Further
143 entries are considered one after one until the operand constraints
144 match or the match-bits and lose-bits do not match. Normally a
145 "further entry" will just show that there was no other match. */
147 static const struct mmix_opcode *
148 get_opcode (unsigned long insn)
150 static const struct mmix_opcode **opcodes = NULL;
151 const struct mmix_opcode *opcodep = mmix_opcodes;
152 unsigned int opcode_part = (insn >> 24) & 255;
155 opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
157 opcodep = opcodes[opcode_part];
159 || (opcodep->match & insn) != opcodep->match
160 || (opcodep->lose & insn) != 0)
162 /* Search through the table. */
163 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
165 /* FIXME: Break out this into an initialization function. */
166 if ((opcodep->match & (opcode_part << 24)) == opcode_part
167 && (opcodep->lose & (opcode_part << 24)) == 0)
168 opcodes[opcode_part] = opcodep;
170 if ((opcodep->match & insn) == opcodep->match
171 && (opcodep->lose & insn) == 0)
176 if (opcodep->name == NULL)
179 /* Check constraints. If they don't match, loop through the next opcode
183 switch (opcodep->operands)
185 /* These have no restraint on what can be in the lower three
187 case mmix_operands_regs:
188 case mmix_operands_reg_yz:
189 case mmix_operands_regs_z_opt:
190 case mmix_operands_regs_z:
191 case mmix_operands_jmp:
192 case mmix_operands_pushgo:
193 case mmix_operands_pop:
194 case mmix_operands_sync:
195 case mmix_operands_x_regs_z:
196 case mmix_operands_neg:
197 case mmix_operands_pushj:
198 case mmix_operands_regaddr:
199 case mmix_operands_get:
200 case mmix_operands_set:
201 case mmix_operands_save:
202 case mmix_operands_unsave:
203 case mmix_operands_xyz_opt:
206 /* For a ROUND_MODE, the middle byte must be 0..4. */
207 case mmix_operands_roundregs_z:
208 case mmix_operands_roundregs:
210 int midbyte = (insn >> 8) & 255;
217 case mmix_operands_put:
218 /* A "PUT". If it is "immediate", then no restrictions,
219 otherwise we have to make sure the register number is < 32. */
220 if ((insn & INSN_IMMEDIATE_BIT)
221 || ((insn >> 16) & 255) < 32)
225 case mmix_operands_resume:
226 /* Middle bytes must be zero. */
227 if ((insn & 0x00ffff00) == 0)
232 BAD_CASE (opcodep->operands);
237 while ((opcodep->match & insn) == opcodep->match
238 && (opcodep->lose & insn) == 0);
240 /* If we got here, we had no match. */
244 /* The main disassembly function. */
247 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
249 unsigned char buffer[4];
251 unsigned int x, y, z;
252 const struct mmix_opcode *opcodep;
253 int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
254 struct mmix_dis_info *minfop;
258 (*info->memory_error_func) (status, memaddr, info);
262 /* FIXME: Is -1 suitable? */
263 if (info->private_data == NULL
264 && ! initialize_mmix_dis_info (info))
267 minfop = (struct mmix_dis_info *) info->private_data;
272 insn = bfd_getb32 (buffer);
274 opcodep = get_opcode (insn);
278 (*info->fprintf_func) (info->stream, _("*unknown*"));
282 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
284 /* Present bytes in the order they are laid out in memory. */
285 info->display_endian = BFD_ENDIAN_BIG;
287 info->insn_info_valid = 1;
288 info->bytes_per_chunk = 4;
289 info->branch_delay_insns = 0;
291 switch (opcodep->type)
293 case mmix_type_normal:
294 case mmix_type_memaccess_block:
295 info->insn_type = dis_nonbranch;
298 case mmix_type_branch:
299 info->insn_type = dis_branch;
302 case mmix_type_condbranch:
303 info->insn_type = dis_condbranch;
306 case mmix_type_memaccess_octa:
307 info->insn_type = dis_dref;
311 case mmix_type_memaccess_tetra:
312 info->insn_type = dis_dref;
316 case mmix_type_memaccess_wyde:
317 info->insn_type = dis_dref;
321 case mmix_type_memaccess_byte:
322 info->insn_type = dis_dref;
327 info->insn_type = dis_jsr;
331 BAD_CASE(opcodep->type);
334 switch (opcodep->operands)
336 case mmix_operands_regs:
337 /* All registers: "$X,$Y,$Z". */
338 (*info->fprintf_func) (info->stream, "%s,%s,%s",
341 minfop->reg_name[z]);
344 case mmix_operands_reg_yz:
345 /* Like SETH - "$X,YZ". */
346 (*info->fprintf_func) (info->stream, "%s,0x%x",
347 minfop->reg_name[x], y * 256 + z);
350 case mmix_operands_regs_z_opt:
351 case mmix_operands_regs_z:
352 case mmix_operands_pushgo:
353 /* The regular "$X,$Y,$Z|Z". */
354 if (insn & INSN_IMMEDIATE_BIT)
355 (*info->fprintf_func) (info->stream, "%s,%s,%d",
356 minfop->reg_name[x], minfop->reg_name[y], z);
358 (*info->fprintf_func) (info->stream, "%s,%s,%s",
361 minfop->reg_name[z]);
364 case mmix_operands_jmp:
365 /* Address; only JMP. */
367 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
369 if (insn & INSN_BACKWARD_OFFSET_BIT)
370 offset -= (256 * 65536) * 4;
372 info->target = memaddr + offset;
373 (*info->print_address_func) (memaddr + offset, info);
377 case mmix_operands_roundregs_z:
378 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
379 "$X,ROUND_MODE,$Z|Z". */
382 if (insn & INSN_IMMEDIATE_BIT)
383 (*info->fprintf_func) (info->stream, "%s,%s,%d",
387 (*info->fprintf_func) (info->stream, "%s,%s,%s",
390 minfop->reg_name[z]);
394 if (insn & INSN_IMMEDIATE_BIT)
395 (*info->fprintf_func) (info->stream, "%s,%d",
396 minfop->reg_name[x], z);
398 (*info->fprintf_func) (info->stream, "%s,%s",
400 minfop->reg_name[z]);
404 case mmix_operands_pop:
405 /* Like POP - "X,YZ". */
406 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
409 case mmix_operands_roundregs:
410 /* Two registers, possibly with rounding: "$X,$Z" or
411 "$X,ROUND_MODE,$Z". */
413 (*info->fprintf_func) (info->stream, "%s,%s,%s",
416 minfop->reg_name[z]);
418 (*info->fprintf_func) (info->stream, "%s,%s",
420 minfop->reg_name[z]);
423 case mmix_operands_sync:
424 /* Like SYNC - "XYZ". */
425 (*info->fprintf_func) (info->stream, "%u",
426 x * 65536 + y * 256 + z);
429 case mmix_operands_x_regs_z:
430 /* Like SYNCD - "X,$Y,$Z|Z". */
431 if (insn & INSN_IMMEDIATE_BIT)
432 (*info->fprintf_func) (info->stream, "%d,%s,%d",
433 x, minfop->reg_name[y], z);
435 (*info->fprintf_func) (info->stream, "%d,%s,%s",
436 x, minfop->reg_name[y],
437 minfop->reg_name[z]);
440 case mmix_operands_neg:
441 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
442 if (insn & INSN_IMMEDIATE_BIT)
443 (*info->fprintf_func) (info->stream, "%s,%d,%d",
444 minfop->reg_name[x], y, z);
446 (*info->fprintf_func) (info->stream, "%s,%d,%s",
447 minfop->reg_name[x], y,
448 minfop->reg_name[z]);
451 case mmix_operands_pushj:
452 case mmix_operands_regaddr:
453 /* Like GETA or branches - "$X,Address". */
455 bfd_signed_vma offset = (y * 256 + z) * 4;
457 if (insn & INSN_BACKWARD_OFFSET_BIT)
460 info->target = memaddr + offset;
462 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
463 (*info->print_address_func) (memaddr + offset, info);
467 case mmix_operands_get:
468 /* GET - "X,spec_reg". */
469 (*info->fprintf_func) (info->stream, "%s,%s",
471 minfop->spec_reg_name[z]);
474 case mmix_operands_put:
475 /* PUT - "spec_reg,$Z|Z". */
476 if (insn & INSN_IMMEDIATE_BIT)
477 (*info->fprintf_func) (info->stream, "%s,%d",
478 minfop->spec_reg_name[x], z);
480 (*info->fprintf_func) (info->stream, "%s,%s",
481 minfop->spec_reg_name[x],
482 minfop->reg_name[z]);
485 case mmix_operands_set:
486 /* Two registers, "$X,$Y". */
487 (*info->fprintf_func) (info->stream, "%s,%s",
489 minfop->reg_name[y]);
492 case mmix_operands_save:
494 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
497 case mmix_operands_unsave:
498 /* UNSAVE - "0,$Z". */
499 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
502 case mmix_operands_xyz_opt:
503 /* Like SWYM or TRAP - "X,Y,Z". */
504 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
507 case mmix_operands_resume:
508 /* Just "Z", like RESUME. */
509 (*info->fprintf_func) (info->stream, "%d", z);
513 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),