1 /* mmix-dis.c -- Disassemble MMIX instructions.
2 Copyright (C) 2000-2017 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. */
24 #include "opcode/mmix.h"
25 #include "disassemble.h"
26 #include "libiberty.h"
34 _("Bad case %d (%s) in %s:%d\n"), \
35 x, #x, __FILE__, __LINE__); \
44 _("Internal: Non-debugged code (test-case missing): %s:%d"),\
45 __FILE__, __LINE__); \
50 #define ROUND_MODE(n) \
51 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \
52 (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \
55 #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
56 #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
60 const char *reg_name[256];
61 const char *spec_reg_name[32];
63 /* Waste a little memory so we don't have to allocate each separately.
64 We could have an array with static contents for these, but on the
65 other hand, we don't have to. */
66 char basic_reg_name[256][sizeof ("$255")];
69 /* Initialize a target-specific array in INFO. */
72 initialize_mmix_dis_info (struct disassemble_info *info)
74 struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
80 memset (minfop, 0, sizeof (*minfop));
82 /* Initialize register names from register symbols. If there's no
83 register section, then there are no register symbols. */
84 if ((info->section != NULL && info->section->owner != NULL)
85 || (info->symbols != NULL
86 && info->symbols[0] != NULL
87 && bfd_asymbol_bfd (info->symbols[0]) != NULL))
89 bfd *abfd = info->section && info->section->owner != NULL
90 ? info->section->owner
91 : bfd_asymbol_bfd (info->symbols[0]);
92 asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
94 if (reg_section != NULL)
96 /* The returned symcount *does* include the ending NULL. */
97 long symsize = bfd_get_symtab_upper_bound (abfd);
98 asymbol **syms = malloc (symsize);
107 nsyms = bfd_canonicalize_symtab (abfd, syms);
109 /* We use the first name for a register. If this is MMO, then
110 it's the name with the first sequence number, presumably the
111 first in the source. */
112 for (i = 0; i < nsyms && syms[i] != NULL; i++)
114 if (syms[i]->section == reg_section
115 && syms[i]->value < 256
116 && minfop->reg_name[syms[i]->value] == NULL)
117 minfop->reg_name[syms[i]->value] = syms[i]->name;
122 /* Fill in the rest with the canonical names. */
123 for (i = 0; i < 256; i++)
124 if (minfop->reg_name[i] == NULL)
126 sprintf (minfop->basic_reg_name[i], "$%ld", i);
127 minfop->reg_name[i] = minfop->basic_reg_name[i];
130 /* We assume it's actually a one-to-one mapping of number-to-name. */
131 for (i = 0; mmix_spec_regs[i].name != NULL; i++)
132 minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
134 info->private_data = (void *) minfop;
138 /* A table indexed by the first byte is constructed as we disassemble each
139 tetrabyte. The contents is a pointer into mmix_insns reflecting the
140 first found entry with matching match-bits and lose-bits. Further
141 entries are considered one after one until the operand constraints
142 match or the match-bits and lose-bits do not match. Normally a
143 "further entry" will just show that there was no other match. */
145 static const struct mmix_opcode *
146 get_opcode (unsigned long insn)
148 static const struct mmix_opcode **opcodes = NULL;
149 const struct mmix_opcode *opcodep = mmix_opcodes;
150 unsigned int opcode_part = (insn >> 24) & 255;
153 opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
155 opcodep = opcodes[opcode_part];
157 || (opcodep->match & insn) != opcodep->match
158 || (opcodep->lose & insn) != 0)
160 /* Search through the table. */
161 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
163 /* FIXME: Break out this into an initialization function. */
164 if ((opcodep->match & (opcode_part << 24)) == opcode_part
165 && (opcodep->lose & (opcode_part << 24)) == 0)
166 opcodes[opcode_part] = opcodep;
168 if ((opcodep->match & insn) == opcodep->match
169 && (opcodep->lose & insn) == 0)
174 if (opcodep->name == NULL)
177 /* Check constraints. If they don't match, loop through the next opcode
181 switch (opcodep->operands)
183 /* These have no restraint on what can be in the lower three
185 case mmix_operands_regs:
186 case mmix_operands_reg_yz:
187 case mmix_operands_regs_z_opt:
188 case mmix_operands_regs_z:
189 case mmix_operands_jmp:
190 case mmix_operands_pushgo:
191 case mmix_operands_pop:
192 case mmix_operands_sync:
193 case mmix_operands_x_regs_z:
194 case mmix_operands_neg:
195 case mmix_operands_pushj:
196 case mmix_operands_regaddr:
197 case mmix_operands_get:
198 case mmix_operands_set:
199 case mmix_operands_save:
200 case mmix_operands_unsave:
201 case mmix_operands_xyz_opt:
204 /* For a ROUND_MODE, the middle byte must be 0..4. */
205 case mmix_operands_roundregs_z:
206 case mmix_operands_roundregs:
208 int midbyte = (insn >> 8) & 255;
215 case mmix_operands_put:
216 /* A "PUT". If it is "immediate", then no restrictions,
217 otherwise we have to make sure the register number is < 32. */
218 if ((insn & INSN_IMMEDIATE_BIT)
219 || ((insn >> 16) & 255) < 32)
223 case mmix_operands_resume:
224 /* Middle bytes must be zero. */
225 if ((insn & 0x00ffff00) == 0)
230 BAD_CASE (opcodep->operands);
235 while ((opcodep->match & insn) == opcodep->match
236 && (opcodep->lose & insn) == 0);
238 /* If we got here, we had no match. */
242 /* The main disassembly function. */
245 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
247 unsigned char buffer[4];
249 unsigned int x, y, z;
250 const struct mmix_opcode *opcodep;
251 int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
252 struct mmix_dis_info *minfop;
256 (*info->memory_error_func) (status, memaddr, info);
260 /* FIXME: Is -1 suitable? */
261 if (info->private_data == NULL
262 && ! initialize_mmix_dis_info (info))
265 minfop = (struct mmix_dis_info *) info->private_data;
270 insn = bfd_getb32 (buffer);
272 opcodep = get_opcode (insn);
276 (*info->fprintf_func) (info->stream, _("*unknown*"));
280 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
282 /* Present bytes in the order they are laid out in memory. */
283 info->display_endian = BFD_ENDIAN_BIG;
285 info->insn_info_valid = 1;
286 info->bytes_per_chunk = 4;
287 info->branch_delay_insns = 0;
289 switch (opcodep->type)
291 case mmix_type_normal:
292 case mmix_type_memaccess_block:
293 info->insn_type = dis_nonbranch;
296 case mmix_type_branch:
297 info->insn_type = dis_branch;
300 case mmix_type_condbranch:
301 info->insn_type = dis_condbranch;
304 case mmix_type_memaccess_octa:
305 info->insn_type = dis_dref;
309 case mmix_type_memaccess_tetra:
310 info->insn_type = dis_dref;
314 case mmix_type_memaccess_wyde:
315 info->insn_type = dis_dref;
319 case mmix_type_memaccess_byte:
320 info->insn_type = dis_dref;
325 info->insn_type = dis_jsr;
329 BAD_CASE(opcodep->type);
332 switch (opcodep->operands)
334 case mmix_operands_regs:
335 /* All registers: "$X,$Y,$Z". */
336 (*info->fprintf_func) (info->stream, "%s,%s,%s",
339 minfop->reg_name[z]);
342 case mmix_operands_reg_yz:
343 /* Like SETH - "$X,YZ". */
344 (*info->fprintf_func) (info->stream, "%s,0x%x",
345 minfop->reg_name[x], y * 256 + z);
348 case mmix_operands_regs_z_opt:
349 case mmix_operands_regs_z:
350 case mmix_operands_pushgo:
351 /* The regular "$X,$Y,$Z|Z". */
352 if (insn & INSN_IMMEDIATE_BIT)
353 (*info->fprintf_func) (info->stream, "%s,%s,%d",
354 minfop->reg_name[x], minfop->reg_name[y], z);
356 (*info->fprintf_func) (info->stream, "%s,%s,%s",
359 minfop->reg_name[z]);
362 case mmix_operands_jmp:
363 /* Address; only JMP. */
365 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
367 if (insn & INSN_BACKWARD_OFFSET_BIT)
368 offset -= (256 * 65536) * 4;
370 info->target = memaddr + offset;
371 (*info->print_address_func) (memaddr + offset, info);
375 case mmix_operands_roundregs_z:
376 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
377 "$X,ROUND_MODE,$Z|Z". */
380 if (insn & INSN_IMMEDIATE_BIT)
381 (*info->fprintf_func) (info->stream, "%s,%s,%d",
385 (*info->fprintf_func) (info->stream, "%s,%s,%s",
388 minfop->reg_name[z]);
392 if (insn & INSN_IMMEDIATE_BIT)
393 (*info->fprintf_func) (info->stream, "%s,%d",
394 minfop->reg_name[x], z);
396 (*info->fprintf_func) (info->stream, "%s,%s",
398 minfop->reg_name[z]);
402 case mmix_operands_pop:
403 /* Like POP - "X,YZ". */
404 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
407 case mmix_operands_roundregs:
408 /* Two registers, possibly with rounding: "$X,$Z" or
409 "$X,ROUND_MODE,$Z". */
411 (*info->fprintf_func) (info->stream, "%s,%s,%s",
414 minfop->reg_name[z]);
416 (*info->fprintf_func) (info->stream, "%s,%s",
418 minfop->reg_name[z]);
421 case mmix_operands_sync:
422 /* Like SYNC - "XYZ". */
423 (*info->fprintf_func) (info->stream, "%u",
424 x * 65536 + y * 256 + z);
427 case mmix_operands_x_regs_z:
428 /* Like SYNCD - "X,$Y,$Z|Z". */
429 if (insn & INSN_IMMEDIATE_BIT)
430 (*info->fprintf_func) (info->stream, "%d,%s,%d",
431 x, minfop->reg_name[y], z);
433 (*info->fprintf_func) (info->stream, "%d,%s,%s",
434 x, minfop->reg_name[y],
435 minfop->reg_name[z]);
438 case mmix_operands_neg:
439 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
440 if (insn & INSN_IMMEDIATE_BIT)
441 (*info->fprintf_func) (info->stream, "%s,%d,%d",
442 minfop->reg_name[x], y, z);
444 (*info->fprintf_func) (info->stream, "%s,%d,%s",
445 minfop->reg_name[x], y,
446 minfop->reg_name[z]);
449 case mmix_operands_pushj:
450 case mmix_operands_regaddr:
451 /* Like GETA or branches - "$X,Address". */
453 bfd_signed_vma offset = (y * 256 + z) * 4;
455 if (insn & INSN_BACKWARD_OFFSET_BIT)
458 info->target = memaddr + offset;
460 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
461 (*info->print_address_func) (memaddr + offset, info);
465 case mmix_operands_get:
466 /* GET - "X,spec_reg". */
467 (*info->fprintf_func) (info->stream, "%s,%s",
469 minfop->spec_reg_name[z]);
472 case mmix_operands_put:
473 /* PUT - "spec_reg,$Z|Z". */
474 if (insn & INSN_IMMEDIATE_BIT)
475 (*info->fprintf_func) (info->stream, "%s,%d",
476 minfop->spec_reg_name[x], z);
478 (*info->fprintf_func) (info->stream, "%s,%s",
479 minfop->spec_reg_name[x],
480 minfop->reg_name[z]);
483 case mmix_operands_set:
484 /* Two registers, "$X,$Y". */
485 (*info->fprintf_func) (info->stream, "%s,%s",
487 minfop->reg_name[y]);
490 case mmix_operands_save:
492 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
495 case mmix_operands_unsave:
496 /* UNSAVE - "0,$Z". */
497 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
500 case mmix_operands_xyz_opt:
501 /* Like SWYM or TRAP - "X,Y,Z". */
502 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
505 case mmix_operands_resume:
506 /* Just "Z", like RESUME. */
507 (*info->fprintf_func) (info->stream, "%d", z);
511 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),