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