1 /* mmix-dis.c -- Disassemble MMIX instructions.
2 Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
3 Written by Hans-Peter Nilsson (hp@bitrange.com)
5 This file is part of GDB and the GNU binutils.
7 GDB and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version 2,
10 or (at your option) any later version.
12 GDB and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 the GNU General Public 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, MA 02110-1301, USA. */
24 #include "opcode/mmix.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 static bfd_boolean initialize_mmix_dis_info
70 PARAMS ((struct disassemble_info
*));
71 static const struct mmix_opcode
*get_opcode
72 PARAMS ((unsigned long));
75 /* Initialize a target-specific array in INFO. */
78 initialize_mmix_dis_info (info
)
79 struct disassemble_info
*info
;
81 struct mmix_dis_info
*minfop
= malloc (sizeof (struct mmix_dis_info
));
87 memset (minfop
, 0, sizeof (*minfop
));
89 /* Initialize register names from register symbols. If there's no
90 register section, then there are no register symbols. */
91 if ((info
->section
!= NULL
&& info
->section
->owner
!= NULL
)
92 || (info
->symbols
!= NULL
93 && info
->symbols
[0] != NULL
94 && bfd_asymbol_bfd (info
->symbols
[0]) != NULL
))
96 bfd
*abfd
= info
->section
&& info
->section
->owner
!= NULL
97 ? info
->section
->owner
98 : bfd_asymbol_bfd (info
->symbols
[0]);
99 asection
*reg_section
= bfd_get_section_by_name (abfd
, "*REG*");
101 if (reg_section
!= NULL
)
103 /* The returned symcount *does* include the ending NULL. */
104 long symsize
= bfd_get_symtab_upper_bound (abfd
);
105 asymbol
**syms
= malloc (symsize
);
114 nsyms
= bfd_canonicalize_symtab (abfd
, syms
);
116 /* We use the first name for a register. If this is MMO, then
117 it's the name with the first sequence number, presumably the
118 first in the source. */
119 for (i
= 0; i
< nsyms
&& syms
[i
] != NULL
; i
++)
121 if (syms
[i
]->section
== reg_section
122 && syms
[i
]->value
< 256
123 && minfop
->reg_name
[syms
[i
]->value
] == NULL
)
124 minfop
->reg_name
[syms
[i
]->value
] = syms
[i
]->name
;
129 /* Fill in the rest with the canonical names. */
130 for (i
= 0; i
< 256; i
++)
131 if (minfop
->reg_name
[i
] == NULL
)
133 sprintf (minfop
->basic_reg_name
[i
], "$%d", i
);
134 minfop
->reg_name
[i
] = minfop
->basic_reg_name
[i
];
137 /* We assume it's actually a one-to-one mapping of number-to-name. */
138 for (i
= 0; mmix_spec_regs
[i
].name
!= NULL
; i
++)
139 minfop
->spec_reg_name
[mmix_spec_regs
[i
].number
] = mmix_spec_regs
[i
].name
;
141 info
->private_data
= (PTR
) minfop
;
145 /* A table indexed by the first byte is constructed as we disassemble each
146 tetrabyte. The contents is a pointer into mmix_insns reflecting the
147 first found entry with matching match-bits and lose-bits. Further
148 entries are considered one after one until the operand constraints
149 match or the match-bits and lose-bits do not match. Normally a
150 "further entry" will just show that there was no other match. */
152 static const struct mmix_opcode
*
156 static const struct mmix_opcode
**opcodes
= NULL
;
157 const struct mmix_opcode
*opcodep
= mmix_opcodes
;
158 unsigned int opcode_part
= (insn
>> 24) & 255;
160 opcodes
= xcalloc (256, sizeof (struct mmix_opcode
*));
162 opcodep
= opcodes
[opcode_part
];
164 || (opcodep
->match
& insn
) != opcodep
->match
165 || (opcodep
->lose
& insn
) != 0)
167 /* Search through the table. */
168 for (opcodep
= mmix_opcodes
; opcodep
->name
!= NULL
; opcodep
++)
170 /* FIXME: Break out this into an initialization function. */
171 if ((opcodep
->match
& (opcode_part
<< 24)) == opcode_part
172 && (opcodep
->lose
& (opcode_part
<< 24)) == 0)
173 opcodes
[opcode_part
] = opcodep
;
175 if ((opcodep
->match
& insn
) == opcodep
->match
176 && (opcodep
->lose
& insn
) == 0)
181 if (opcodep
->name
== NULL
)
184 /* Check constraints. If they don't match, loop through the next opcode
188 switch (opcodep
->operands
)
190 /* These have no restraint on what can be in the lower three
192 case mmix_operands_regs
:
193 case mmix_operands_reg_yz
:
194 case mmix_operands_regs_z_opt
:
195 case mmix_operands_regs_z
:
196 case mmix_operands_jmp
:
197 case mmix_operands_pushgo
:
198 case mmix_operands_pop
:
199 case mmix_operands_sync
:
200 case mmix_operands_x_regs_z
:
201 case mmix_operands_neg
:
202 case mmix_operands_pushj
:
203 case mmix_operands_regaddr
:
204 case mmix_operands_get
:
205 case mmix_operands_set
:
206 case mmix_operands_save
:
207 case mmix_operands_unsave
:
208 case mmix_operands_xyz_opt
:
211 /* For a ROUND_MODE, the middle byte must be 0..4. */
212 case mmix_operands_roundregs_z
:
213 case mmix_operands_roundregs
:
215 int midbyte
= (insn
>> 8) & 255;
221 case mmix_operands_put
:
222 /* A "PUT". If it is "immediate", then no restrictions,
223 otherwise we have to make sure the register number is < 32. */
224 if ((insn
& INSN_IMMEDIATE_BIT
)
225 || ((insn
>> 16) & 255) < 32)
229 case mmix_operands_resume
:
230 /* Middle bytes must be zero. */
231 if ((insn
& 0x00ffff00) == 0)
236 BAD_CASE (opcodep
->operands
);
241 while ((opcodep
->match
& insn
) == opcodep
->match
242 && (opcodep
->lose
& insn
) == 0);
244 /* If we got here, we had no match. */
248 /* The main disassembly function. */
251 print_insn_mmix (memaddr
, info
)
253 struct disassemble_info
*info
;
255 unsigned char buffer
[4];
257 unsigned int x
, y
, z
;
258 const struct mmix_opcode
*opcodep
;
259 int status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
260 struct mmix_dis_info
*minfop
;
264 (*info
->memory_error_func
) (status
, memaddr
, info
);
268 /* FIXME: Is -1 suitable? */
269 if (info
->private_data
== NULL
270 && ! initialize_mmix_dis_info (info
))
273 minfop
= (struct mmix_dis_info
*) info
->private_data
;
278 insn
= bfd_getb32 (buffer
);
280 opcodep
= get_opcode (insn
);
284 (*info
->fprintf_func
) (info
->stream
, _("*unknown*"));
288 (*info
->fprintf_func
) (info
->stream
, "%s ", opcodep
->name
);
290 /* Present bytes in the order they are laid out in memory. */
291 info
->display_endian
= BFD_ENDIAN_BIG
;
293 info
->insn_info_valid
= 1;
294 info
->bytes_per_chunk
= 4;
295 info
->branch_delay_insns
= 0;
297 switch (opcodep
->type
)
299 case mmix_type_normal
:
300 case mmix_type_memaccess_block
:
301 info
->insn_type
= dis_nonbranch
;
304 case mmix_type_branch
:
305 info
->insn_type
= dis_branch
;
308 case mmix_type_condbranch
:
309 info
->insn_type
= dis_condbranch
;
312 case mmix_type_memaccess_octa
:
313 info
->insn_type
= dis_dref
;
317 case mmix_type_memaccess_tetra
:
318 info
->insn_type
= dis_dref
;
322 case mmix_type_memaccess_wyde
:
323 info
->insn_type
= dis_dref
;
327 case mmix_type_memaccess_byte
:
328 info
->insn_type
= dis_dref
;
333 info
->insn_type
= dis_jsr
;
337 BAD_CASE(opcodep
->type
);
340 switch (opcodep
->operands
)
342 case mmix_operands_regs
:
343 /* All registers: "$X,$Y,$Z". */
344 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%s",
347 minfop
->reg_name
[z
]);
350 case mmix_operands_reg_yz
:
351 /* Like SETH - "$X,YZ". */
352 (*info
->fprintf_func
) (info
->stream
, "%s,0x%x",
353 minfop
->reg_name
[x
], y
* 256 + z
);
356 case mmix_operands_regs_z_opt
:
357 case mmix_operands_regs_z
:
358 case mmix_operands_pushgo
:
359 /* The regular "$X,$Y,$Z|Z". */
360 if (insn
& INSN_IMMEDIATE_BIT
)
361 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%d",
362 minfop
->reg_name
[x
], minfop
->reg_name
[y
], z
);
364 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%s",
367 minfop
->reg_name
[z
]);
370 case mmix_operands_jmp
:
371 /* Address; only JMP. */
373 bfd_signed_vma offset
= (x
* 65536 + y
* 256 + z
) * 4;
375 if (insn
& INSN_BACKWARD_OFFSET_BIT
)
376 offset
-= (256 * 65536) * 4;
378 info
->target
= memaddr
+ offset
;
379 (*info
->print_address_func
) (memaddr
+ offset
, info
);
383 case mmix_operands_roundregs_z
:
384 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
385 "$X,ROUND_MODE,$Z|Z". */
388 if (insn
& INSN_IMMEDIATE_BIT
)
389 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%d",
393 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%s",
396 minfop
->reg_name
[z
]);
400 if (insn
& INSN_IMMEDIATE_BIT
)
401 (*info
->fprintf_func
) (info
->stream
, "%s,%d",
402 minfop
->reg_name
[x
], z
);
404 (*info
->fprintf_func
) (info
->stream
, "%s,%s",
406 minfop
->reg_name
[z
]);
410 case mmix_operands_pop
:
411 /* Like POP - "X,YZ". */
412 (*info
->fprintf_func
) (info
->stream
, "%d,%d", x
, y
*256 + z
);
415 case mmix_operands_roundregs
:
416 /* Two registers, possibly with rounding: "$X,$Z" or
417 "$X,ROUND_MODE,$Z". */
419 (*info
->fprintf_func
) (info
->stream
, "%s,%s,%s",
422 minfop
->reg_name
[z
]);
424 (*info
->fprintf_func
) (info
->stream
, "%s,%s",
426 minfop
->reg_name
[z
]);
429 case mmix_operands_sync
:
430 /* Like SYNC - "XYZ". */
431 (*info
->fprintf_func
) (info
->stream
, "%u",
432 x
* 65536 + y
* 256 + z
);
435 case mmix_operands_x_regs_z
:
436 /* Like SYNCD - "X,$Y,$Z|Z". */
437 if (insn
& INSN_IMMEDIATE_BIT
)
438 (*info
->fprintf_func
) (info
->stream
, "%d,%s,%d",
439 x
, minfop
->reg_name
[y
], z
);
441 (*info
->fprintf_func
) (info
->stream
, "%d,%s,%s",
442 x
, minfop
->reg_name
[y
],
443 minfop
->reg_name
[z
]);
446 case mmix_operands_neg
:
447 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
448 if (insn
& INSN_IMMEDIATE_BIT
)
449 (*info
->fprintf_func
) (info
->stream
, "%s,%d,%d",
450 minfop
->reg_name
[x
], y
, z
);
452 (*info
->fprintf_func
) (info
->stream
, "%s,%d,%s",
453 minfop
->reg_name
[x
], y
,
454 minfop
->reg_name
[z
]);
457 case mmix_operands_pushj
:
458 case mmix_operands_regaddr
:
459 /* Like GETA or branches - "$X,Address". */
461 bfd_signed_vma offset
= (y
* 256 + z
) * 4;
463 if (insn
& INSN_BACKWARD_OFFSET_BIT
)
466 info
->target
= memaddr
+ offset
;
468 (*info
->fprintf_func
) (info
->stream
, "%s,", minfop
->reg_name
[x
]);
469 (*info
->print_address_func
) (memaddr
+ offset
, info
);
473 case mmix_operands_get
:
474 /* GET - "X,spec_reg". */
475 (*info
->fprintf_func
) (info
->stream
, "%s,%s",
477 minfop
->spec_reg_name
[z
]);
480 case mmix_operands_put
:
481 /* PUT - "spec_reg,$Z|Z". */
482 if (insn
& INSN_IMMEDIATE_BIT
)
483 (*info
->fprintf_func
) (info
->stream
, "%s,%d",
484 minfop
->spec_reg_name
[x
], z
);
486 (*info
->fprintf_func
) (info
->stream
, "%s,%s",
487 minfop
->spec_reg_name
[x
],
488 minfop
->reg_name
[z
]);
491 case mmix_operands_set
:
492 /* Two registers, "$X,$Y". */
493 (*info
->fprintf_func
) (info
->stream
, "%s,%s",
495 minfop
->reg_name
[y
]);
498 case mmix_operands_save
:
500 (*info
->fprintf_func
) (info
->stream
, "%s,0", minfop
->reg_name
[x
]);
503 case mmix_operands_unsave
:
504 /* UNSAVE - "0,$Z". */
505 (*info
->fprintf_func
) (info
->stream
, "0,%s", minfop
->reg_name
[z
]);
508 case mmix_operands_xyz_opt
:
509 /* Like SWYM or TRAP - "X,Y,Z". */
510 (*info
->fprintf_func
) (info
->stream
, "%d,%d,%d", x
, y
, z
);
513 case mmix_operands_resume
:
514 /* Just "Z", like RESUME. */
515 (*info
->fprintf_func
) (info
->stream
, "%d", z
);
519 (*info
->fprintf_func
) (info
->stream
, _("*unknown operands type: %d*"),