]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/mmix-dis.c
Update year range in copyright notice of all files.
[thirdparty/binutils-gdb.git] / opcodes / mmix-dis.c
CommitLineData
afd30973 1/* mmix-dis.c -- Disassemble MMIX instructions.
2571583a 2 Copyright (C) 2000-2017 Free Software Foundation, Inc.
afd30973
HPN
3 Written by Hans-Peter Nilsson (hp@bitrange.com)
4
9b201bb5 5 This file is part of the GNU opcodes library.
afd30973 6
9b201bb5
NC
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)
10 any later version.
afd30973 11
9b201bb5
NC
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.
afd30973 16
47b0e7ad
NC
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. */
afd30973 21
5eb3690e 22#include "sysdep.h"
afd30973 23#include <stdio.h>
afd30973
HPN
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
47b0e7ad
NC
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 } \
afd30973
HPN
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
afd30973
HPN
69/* Initialize a target-specific array in INFO. */
70
b34976b6 71static bfd_boolean
47b0e7ad 72initialize_mmix_dis_info (struct disassemble_info *info)
afd30973
HPN
73{
74 struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
91d6fa6a 75 long i;
afd30973
HPN
76
77 if (minfop == NULL)
b34976b6 78 return FALSE;
afd30973
HPN
79
80 memset (minfop, 0, sizeof (*minfop));
81
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))
88 {
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*");
93
94 if (reg_section != NULL)
95 {
96 /* The returned symcount *does* include the ending NULL. */
97 long symsize = bfd_get_symtab_upper_bound (abfd);
98 asymbol **syms = malloc (symsize);
99 long nsyms;
afd30973
HPN
100
101 if (syms == NULL)
47b0e7ad
NC
102 {
103 FATAL_DEBUG;
afd30973 104 free (minfop);
b34976b6 105 return FALSE;
afd30973
HPN
106 }
107 nsyms = bfd_canonicalize_symtab (abfd, syms);
108
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++)
113 {
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;
118 }
119 }
120 }
121
122 /* Fill in the rest with the canonical names. */
123 for (i = 0; i < 256; i++)
124 if (minfop->reg_name[i] == NULL)
125 {
91d6fa6a 126 sprintf (minfop->basic_reg_name[i], "$%ld", i);
afd30973
HPN
127 minfop->reg_name[i] = minfop->basic_reg_name[i];
128 }
129
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;
133
47b0e7ad 134 info->private_data = (void *) minfop;
b34976b6 135 return TRUE;
afd30973
HPN
136}
137
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. */
144
145static const struct mmix_opcode *
47b0e7ad 146get_opcode (unsigned long insn)
afd30973
HPN
147{
148 static const struct mmix_opcode **opcodes = NULL;
149 const struct mmix_opcode *opcodep = mmix_opcodes;
150 unsigned int opcode_part = (insn >> 24) & 255;
47b0e7ad 151
afd30973
HPN
152 if (opcodes == NULL)
153 opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
154
155 opcodep = opcodes[opcode_part];
156 if (opcodep == NULL
157 || (opcodep->match & insn) != opcodep->match
158 || (opcodep->lose & insn) != 0)
159 {
160 /* Search through the table. */
161 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
162 {
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;
167
168 if ((opcodep->match & insn) == opcodep->match
169 && (opcodep->lose & insn) == 0)
170 break;
171 }
172 }
173
174 if (opcodep->name == NULL)
175 return NULL;
176
177 /* Check constraints. If they don't match, loop through the next opcode
178 entries. */
179 do
180 {
181 switch (opcodep->operands)
182 {
183 /* These have no restraint on what can be in the lower three
184 bytes. */
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:
202 return opcodep;
203
204 /* For a ROUND_MODE, the middle byte must be 0..4. */
205 case mmix_operands_roundregs_z:
206 case mmix_operands_roundregs:
207 {
208 int midbyte = (insn >> 8) & 255;
47b0e7ad 209
afd30973
HPN
210 if (midbyte <= 4)
211 return opcodep;
212 }
213 break;
214
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)
220 return opcodep;
221 break;
222
223 case mmix_operands_resume:
224 /* Middle bytes must be zero. */
225 if ((insn & 0x00ffff00) == 0)
226 return opcodep;
227 break;
228
229 default:
230 BAD_CASE (opcodep->operands);
231 }
232
233 opcodep++;
234 }
235 while ((opcodep->match & insn) == opcodep->match
236 && (opcodep->lose & insn) == 0);
237
238 /* If we got here, we had no match. */
239 return NULL;
240}
241
242/* The main disassembly function. */
243
244int
47b0e7ad 245print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
afd30973
HPN
246{
247 unsigned char buffer[4];
248 unsigned long insn;
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;
253
254 if (status != 0)
255 {
256 (*info->memory_error_func) (status, memaddr, info);
257 return -1;
258 }
259
260 /* FIXME: Is -1 suitable? */
261 if (info->private_data == NULL
262 && ! initialize_mmix_dis_info (info))
263 return -1;
264
265 minfop = (struct mmix_dis_info *) info->private_data;
266 x = buffer[1];
267 y = buffer[2];
268 z = buffer[3];
269
270 insn = bfd_getb32 (buffer);
271
272 opcodep = get_opcode (insn);
273
274 if (opcodep == NULL)
275 {
276 (*info->fprintf_func) (info->stream, _("*unknown*"));
277 return 4;
278 }
279
280 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
281
282 /* Present bytes in the order they are laid out in memory. */
283 info->display_endian = BFD_ENDIAN_BIG;
284
285 info->insn_info_valid = 1;
286 info->bytes_per_chunk = 4;
287 info->branch_delay_insns = 0;
288 info->target = 0;
289 switch (opcodep->type)
290 {
291 case mmix_type_normal:
292 case mmix_type_memaccess_block:
293 info->insn_type = dis_nonbranch;
294 break;
295
296 case mmix_type_branch:
297 info->insn_type = dis_branch;
298 break;
299
300 case mmix_type_condbranch:
301 info->insn_type = dis_condbranch;
302 break;
303
304 case mmix_type_memaccess_octa:
305 info->insn_type = dis_dref;
306 info->data_size = 8;
307 break;
308
309 case mmix_type_memaccess_tetra:
310 info->insn_type = dis_dref;
311 info->data_size = 4;
312 break;
313
314 case mmix_type_memaccess_wyde:
315 info->insn_type = dis_dref;
316 info->data_size = 2;
317 break;
318
319 case mmix_type_memaccess_byte:
320 info->insn_type = dis_dref;
321 info->data_size = 1;
322 break;
323
324 case mmix_type_jsr:
325 info->insn_type = dis_jsr;
326 break;
327
328 default:
329 BAD_CASE(opcodep->type);
330 }
331
332 switch (opcodep->operands)
333 {
334 case mmix_operands_regs:
335 /* All registers: "$X,$Y,$Z". */
336 (*info->fprintf_func) (info->stream, "%s,%s,%s",
337 minfop->reg_name[x],
338 minfop->reg_name[y],
339 minfop->reg_name[z]);
340 break;
341
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);
346 break;
347
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);
355 else
356 (*info->fprintf_func) (info->stream, "%s,%s,%s",
357 minfop->reg_name[x],
358 minfop->reg_name[y],
359 minfop->reg_name[z]);
360 break;
361
362 case mmix_operands_jmp:
363 /* Address; only JMP. */
364 {
365 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
366
367 if (insn & INSN_BACKWARD_OFFSET_BIT)
368 offset -= (256 * 65536) * 4;
369
370 info->target = memaddr + offset;
371 (*info->print_address_func) (memaddr + offset, info);
372 }
373 break;
374
375 case mmix_operands_roundregs_z:
376 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
377 "$X,ROUND_MODE,$Z|Z". */
378 if (y != 0)
379 {
380 if (insn & INSN_IMMEDIATE_BIT)
381 (*info->fprintf_func) (info->stream, "%s,%s,%d",
382 minfop->reg_name[x],
383 ROUND_MODE (y), z);
384 else
385 (*info->fprintf_func) (info->stream, "%s,%s,%s",
386 minfop->reg_name[x],
387 ROUND_MODE (y),
388 minfop->reg_name[z]);
389 }
390 else
391 {
392 if (insn & INSN_IMMEDIATE_BIT)
393 (*info->fprintf_func) (info->stream, "%s,%d",
394 minfop->reg_name[x], z);
395 else
396 (*info->fprintf_func) (info->stream, "%s,%s",
397 minfop->reg_name[x],
398 minfop->reg_name[z]);
399 }
400 break;
401
402 case mmix_operands_pop:
403 /* Like POP - "X,YZ". */
404 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
405 break;
406
407 case mmix_operands_roundregs:
408 /* Two registers, possibly with rounding: "$X,$Z" or
409 "$X,ROUND_MODE,$Z". */
410 if (y != 0)
411 (*info->fprintf_func) (info->stream, "%s,%s,%s",
412 minfop->reg_name[x],
413 ROUND_MODE (y),
414 minfop->reg_name[z]);
415 else
416 (*info->fprintf_func) (info->stream, "%s,%s",
417 minfop->reg_name[x],
418 minfop->reg_name[z]);
419 break;
420
421 case mmix_operands_sync:
422 /* Like SYNC - "XYZ". */
423 (*info->fprintf_func) (info->stream, "%u",
424 x * 65536 + y * 256 + z);
425 break;
426
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);
432 else
433 (*info->fprintf_func) (info->stream, "%d,%s,%s",
434 x, minfop->reg_name[y],
435 minfop->reg_name[z]);
436 break;
437
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);
443 else
444 (*info->fprintf_func) (info->stream, "%s,%d,%s",
445 minfop->reg_name[x], y,
446 minfop->reg_name[z]);
447 break;
448
449 case mmix_operands_pushj:
450 case mmix_operands_regaddr:
451 /* Like GETA or branches - "$X,Address". */
452 {
453 bfd_signed_vma offset = (y * 256 + z) * 4;
454
455 if (insn & INSN_BACKWARD_OFFSET_BIT)
456 offset -= 65536 * 4;
457
458 info->target = memaddr + offset;
459
460 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
461 (*info->print_address_func) (memaddr + offset, info);
462 }
463 break;
464
465 case mmix_operands_get:
466 /* GET - "X,spec_reg". */
467 (*info->fprintf_func) (info->stream, "%s,%s",
468 minfop->reg_name[x],
469 minfop->spec_reg_name[z]);
470 break;
471
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);
477 else
478 (*info->fprintf_func) (info->stream, "%s,%s",
479 minfop->spec_reg_name[x],
480 minfop->reg_name[z]);
481 break;
482
483 case mmix_operands_set:
484 /* Two registers, "$X,$Y". */
485 (*info->fprintf_func) (info->stream, "%s,%s",
486 minfop->reg_name[x],
487 minfop->reg_name[y]);
488 break;
489
490 case mmix_operands_save:
491 /* SAVE - "$X,0". */
492 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
493 break;
494
495 case mmix_operands_unsave:
496 /* UNSAVE - "0,$Z". */
497 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
498 break;
499
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);
503 break;
504
505 case mmix_operands_resume:
506 /* Just "Z", like RESUME. */
507 (*info->fprintf_func) (info->stream, "%d", z);
508 break;
509
510 default:
511 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
512 opcodep->operands);
513 break;
514 }
515
516 return 4;
517}