]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/mmix-dis.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / opcodes / mmix-dis.c
1 /* mmix-dis.c -- Disassemble MMIX instructions.
2 Copyright (C) 2000-2019 Free Software Foundation, Inc.
3 Written by Hans-Peter Nilsson (hp@bitrange.com)
4
5 This file is part of the GNU opcodes library.
6
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.
11
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.
16
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. */
21
22 #include "sysdep.h"
23 #include <stdio.h>
24 #include "opcode/mmix.h"
25 #include "disassemble.h"
26 #include "libiberty.h"
27 #include "bfd.h"
28 #include "opintl.h"
29
30 #define BAD_CASE(x) \
31 do \
32 { \
33 opcodes_error_handler (_("bad case %d (%s) in %s:%d"), \
34 x, #x, __FILE__, __LINE__); \
35 abort (); \
36 } \
37 while (0)
38
39 #define FATAL_DEBUG \
40 do \
41 { \
42 opcodes_error_handler (_("internal: non-debugged code " \
43 "(test-case missing): %s:%d"), \
44 __FILE__, __LINE__); \
45 abort (); \
46 } \
47 while (0)
48
49 #define ROUND_MODE(n) \
50 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \
51 (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \
52 _("(unknown)"))
53
54 #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
55 #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
56
57 struct mmix_dis_info
58 {
59 const char *reg_name[256];
60 const char *spec_reg_name[32];
61
62 /* Waste a little memory so we don't have to allocate each separately.
63 We could have an array with static contents for these, but on the
64 other hand, we don't have to. */
65 char basic_reg_name[256][sizeof ("$255")];
66 };
67
68 /* Initialize a target-specific array in INFO. */
69
70 static bfd_boolean
71 initialize_mmix_dis_info (struct disassemble_info *info)
72 {
73 struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
74 long i;
75
76 if (minfop == NULL)
77 return FALSE;
78
79 memset (minfop, 0, sizeof (*minfop));
80
81 /* Initialize register names from register symbols. If there's no
82 register section, then there are no register symbols. */
83 if ((info->section != NULL && info->section->owner != NULL)
84 || (info->symbols != NULL
85 && info->symbols[0] != NULL
86 && bfd_asymbol_bfd (info->symbols[0]) != NULL))
87 {
88 bfd *abfd = info->section && info->section->owner != NULL
89 ? info->section->owner
90 : bfd_asymbol_bfd (info->symbols[0]);
91 asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
92
93 if (reg_section != NULL)
94 {
95 /* The returned symcount *does* include the ending NULL. */
96 long symsize = bfd_get_symtab_upper_bound (abfd);
97 asymbol **syms = malloc (symsize);
98 long nsyms;
99
100 if (syms == NULL)
101 {
102 FATAL_DEBUG;
103 free (minfop);
104 return FALSE;
105 }
106 nsyms = bfd_canonicalize_symtab (abfd, syms);
107
108 /* We use the first name for a register. If this is MMO, then
109 it's the name with the first sequence number, presumably the
110 first in the source. */
111 for (i = 0; i < nsyms && syms[i] != NULL; i++)
112 {
113 if (syms[i]->section == reg_section
114 && syms[i]->value < 256
115 && minfop->reg_name[syms[i]->value] == NULL)
116 minfop->reg_name[syms[i]->value] = syms[i]->name;
117 }
118 }
119 }
120
121 /* Fill in the rest with the canonical names. */
122 for (i = 0; i < 256; i++)
123 if (minfop->reg_name[i] == NULL)
124 {
125 sprintf (minfop->basic_reg_name[i], "$%ld", i);
126 minfop->reg_name[i] = minfop->basic_reg_name[i];
127 }
128
129 /* We assume it's actually a one-to-one mapping of number-to-name. */
130 for (i = 0; mmix_spec_regs[i].name != NULL; i++)
131 minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
132
133 info->private_data = (void *) minfop;
134 return TRUE;
135 }
136
137 /* A table indexed by the first byte is constructed as we disassemble each
138 tetrabyte. The contents is a pointer into mmix_insns reflecting the
139 first found entry with matching match-bits and lose-bits. Further
140 entries are considered one after one until the operand constraints
141 match or the match-bits and lose-bits do not match. Normally a
142 "further entry" will just show that there was no other match. */
143
144 static const struct mmix_opcode *
145 get_opcode (unsigned long insn)
146 {
147 static const struct mmix_opcode **opcodes = NULL;
148 const struct mmix_opcode *opcodep = mmix_opcodes;
149 unsigned int opcode_part = (insn >> 24) & 255;
150
151 if (opcodes == NULL)
152 opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
153
154 opcodep = opcodes[opcode_part];
155 if (opcodep == NULL
156 || (opcodep->match & insn) != opcodep->match
157 || (opcodep->lose & insn) != 0)
158 {
159 /* Search through the table. */
160 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
161 {
162 /* FIXME: Break out this into an initialization function. */
163 if ((opcodep->match & (opcode_part << 24)) == opcode_part
164 && (opcodep->lose & (opcode_part << 24)) == 0)
165 opcodes[opcode_part] = opcodep;
166
167 if ((opcodep->match & insn) == opcodep->match
168 && (opcodep->lose & insn) == 0)
169 break;
170 }
171 }
172
173 if (opcodep->name == NULL)
174 return NULL;
175
176 /* Check constraints. If they don't match, loop through the next opcode
177 entries. */
178 do
179 {
180 switch (opcodep->operands)
181 {
182 /* These have no restraint on what can be in the lower three
183 bytes. */
184 case mmix_operands_regs:
185 case mmix_operands_reg_yz:
186 case mmix_operands_regs_z_opt:
187 case mmix_operands_regs_z:
188 case mmix_operands_jmp:
189 case mmix_operands_pushgo:
190 case mmix_operands_pop:
191 case mmix_operands_sync:
192 case mmix_operands_x_regs_z:
193 case mmix_operands_neg:
194 case mmix_operands_pushj:
195 case mmix_operands_regaddr:
196 case mmix_operands_get:
197 case mmix_operands_set:
198 case mmix_operands_save:
199 case mmix_operands_unsave:
200 case mmix_operands_xyz_opt:
201 return opcodep;
202
203 /* For a ROUND_MODE, the middle byte must be 0..4. */
204 case mmix_operands_roundregs_z:
205 case mmix_operands_roundregs:
206 {
207 int midbyte = (insn >> 8) & 255;
208
209 if (midbyte <= 4)
210 return opcodep;
211 }
212 break;
213
214 case mmix_operands_put:
215 /* A "PUT". If it is "immediate", then no restrictions,
216 otherwise we have to make sure the register number is < 32. */
217 if ((insn & INSN_IMMEDIATE_BIT)
218 || ((insn >> 16) & 255) < 32)
219 return opcodep;
220 break;
221
222 case mmix_operands_resume:
223 /* Middle bytes must be zero. */
224 if ((insn & 0x00ffff00) == 0)
225 return opcodep;
226 break;
227
228 default:
229 BAD_CASE (opcodep->operands);
230 }
231
232 opcodep++;
233 }
234 while ((opcodep->match & insn) == opcodep->match
235 && (opcodep->lose & insn) == 0);
236
237 /* If we got here, we had no match. */
238 return NULL;
239 }
240
241 /* The main disassembly function. */
242
243 int
244 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
245 {
246 unsigned char buffer[4];
247 unsigned long insn;
248 unsigned int x, y, z;
249 const struct mmix_opcode *opcodep;
250 int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
251 struct mmix_dis_info *minfop;
252
253 if (status != 0)
254 {
255 (*info->memory_error_func) (status, memaddr, info);
256 return -1;
257 }
258
259 /* FIXME: Is -1 suitable? */
260 if (info->private_data == NULL
261 && ! initialize_mmix_dis_info (info))
262 return -1;
263
264 minfop = (struct mmix_dis_info *) info->private_data;
265 x = buffer[1];
266 y = buffer[2];
267 z = buffer[3];
268
269 insn = bfd_getb32 (buffer);
270
271 opcodep = get_opcode (insn);
272
273 if (opcodep == NULL)
274 {
275 (*info->fprintf_func) (info->stream, _("*unknown*"));
276 return 4;
277 }
278
279 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
280
281 /* Present bytes in the order they are laid out in memory. */
282 info->display_endian = BFD_ENDIAN_BIG;
283
284 info->insn_info_valid = 1;
285 info->bytes_per_chunk = 4;
286 info->branch_delay_insns = 0;
287 info->target = 0;
288 switch (opcodep->type)
289 {
290 case mmix_type_normal:
291 case mmix_type_memaccess_block:
292 info->insn_type = dis_nonbranch;
293 break;
294
295 case mmix_type_branch:
296 info->insn_type = dis_branch;
297 break;
298
299 case mmix_type_condbranch:
300 info->insn_type = dis_condbranch;
301 break;
302
303 case mmix_type_memaccess_octa:
304 info->insn_type = dis_dref;
305 info->data_size = 8;
306 break;
307
308 case mmix_type_memaccess_tetra:
309 info->insn_type = dis_dref;
310 info->data_size = 4;
311 break;
312
313 case mmix_type_memaccess_wyde:
314 info->insn_type = dis_dref;
315 info->data_size = 2;
316 break;
317
318 case mmix_type_memaccess_byte:
319 info->insn_type = dis_dref;
320 info->data_size = 1;
321 break;
322
323 case mmix_type_jsr:
324 info->insn_type = dis_jsr;
325 break;
326
327 default:
328 BAD_CASE(opcodep->type);
329 }
330
331 switch (opcodep->operands)
332 {
333 case mmix_operands_regs:
334 /* All registers: "$X,$Y,$Z". */
335 (*info->fprintf_func) (info->stream, "%s,%s,%s",
336 minfop->reg_name[x],
337 minfop->reg_name[y],
338 minfop->reg_name[z]);
339 break;
340
341 case mmix_operands_reg_yz:
342 /* Like SETH - "$X,YZ". */
343 (*info->fprintf_func) (info->stream, "%s,0x%x",
344 minfop->reg_name[x], y * 256 + z);
345 break;
346
347 case mmix_operands_regs_z_opt:
348 case mmix_operands_regs_z:
349 case mmix_operands_pushgo:
350 /* The regular "$X,$Y,$Z|Z". */
351 if (insn & INSN_IMMEDIATE_BIT)
352 (*info->fprintf_func) (info->stream, "%s,%s,%d",
353 minfop->reg_name[x], minfop->reg_name[y], z);
354 else
355 (*info->fprintf_func) (info->stream, "%s,%s,%s",
356 minfop->reg_name[x],
357 minfop->reg_name[y],
358 minfop->reg_name[z]);
359 break;
360
361 case mmix_operands_jmp:
362 /* Address; only JMP. */
363 {
364 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
365
366 if (insn & INSN_BACKWARD_OFFSET_BIT)
367 offset -= (256 * 65536) * 4;
368
369 info->target = memaddr + offset;
370 (*info->print_address_func) (memaddr + offset, info);
371 }
372 break;
373
374 case mmix_operands_roundregs_z:
375 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
376 "$X,ROUND_MODE,$Z|Z". */
377 if (y != 0)
378 {
379 if (insn & INSN_IMMEDIATE_BIT)
380 (*info->fprintf_func) (info->stream, "%s,%s,%d",
381 minfop->reg_name[x],
382 ROUND_MODE (y), z);
383 else
384 (*info->fprintf_func) (info->stream, "%s,%s,%s",
385 minfop->reg_name[x],
386 ROUND_MODE (y),
387 minfop->reg_name[z]);
388 }
389 else
390 {
391 if (insn & INSN_IMMEDIATE_BIT)
392 (*info->fprintf_func) (info->stream, "%s,%d",
393 minfop->reg_name[x], z);
394 else
395 (*info->fprintf_func) (info->stream, "%s,%s",
396 minfop->reg_name[x],
397 minfop->reg_name[z]);
398 }
399 break;
400
401 case mmix_operands_pop:
402 /* Like POP - "X,YZ". */
403 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
404 break;
405
406 case mmix_operands_roundregs:
407 /* Two registers, possibly with rounding: "$X,$Z" or
408 "$X,ROUND_MODE,$Z". */
409 if (y != 0)
410 (*info->fprintf_func) (info->stream, "%s,%s,%s",
411 minfop->reg_name[x],
412 ROUND_MODE (y),
413 minfop->reg_name[z]);
414 else
415 (*info->fprintf_func) (info->stream, "%s,%s",
416 minfop->reg_name[x],
417 minfop->reg_name[z]);
418 break;
419
420 case mmix_operands_sync:
421 /* Like SYNC - "XYZ". */
422 (*info->fprintf_func) (info->stream, "%u",
423 x * 65536 + y * 256 + z);
424 break;
425
426 case mmix_operands_x_regs_z:
427 /* Like SYNCD - "X,$Y,$Z|Z". */
428 if (insn & INSN_IMMEDIATE_BIT)
429 (*info->fprintf_func) (info->stream, "%d,%s,%d",
430 x, minfop->reg_name[y], z);
431 else
432 (*info->fprintf_func) (info->stream, "%d,%s,%s",
433 x, minfop->reg_name[y],
434 minfop->reg_name[z]);
435 break;
436
437 case mmix_operands_neg:
438 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
439 if (insn & INSN_IMMEDIATE_BIT)
440 (*info->fprintf_func) (info->stream, "%s,%d,%d",
441 minfop->reg_name[x], y, z);
442 else
443 (*info->fprintf_func) (info->stream, "%s,%d,%s",
444 minfop->reg_name[x], y,
445 minfop->reg_name[z]);
446 break;
447
448 case mmix_operands_pushj:
449 case mmix_operands_regaddr:
450 /* Like GETA or branches - "$X,Address". */
451 {
452 bfd_signed_vma offset = (y * 256 + z) * 4;
453
454 if (insn & INSN_BACKWARD_OFFSET_BIT)
455 offset -= 65536 * 4;
456
457 info->target = memaddr + offset;
458
459 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
460 (*info->print_address_func) (memaddr + offset, info);
461 }
462 break;
463
464 case mmix_operands_get:
465 /* GET - "X,spec_reg". */
466 (*info->fprintf_func) (info->stream, "%s,%s",
467 minfop->reg_name[x],
468 minfop->spec_reg_name[z]);
469 break;
470
471 case mmix_operands_put:
472 /* PUT - "spec_reg,$Z|Z". */
473 if (insn & INSN_IMMEDIATE_BIT)
474 (*info->fprintf_func) (info->stream, "%s,%d",
475 minfop->spec_reg_name[x], z);
476 else
477 (*info->fprintf_func) (info->stream, "%s,%s",
478 minfop->spec_reg_name[x],
479 minfop->reg_name[z]);
480 break;
481
482 case mmix_operands_set:
483 /* Two registers, "$X,$Y". */
484 (*info->fprintf_func) (info->stream, "%s,%s",
485 minfop->reg_name[x],
486 minfop->reg_name[y]);
487 break;
488
489 case mmix_operands_save:
490 /* SAVE - "$X,0". */
491 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
492 break;
493
494 case mmix_operands_unsave:
495 /* UNSAVE - "0,$Z". */
496 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
497 break;
498
499 case mmix_operands_xyz_opt:
500 /* Like SWYM or TRAP - "X,Y,Z". */
501 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
502 break;
503
504 case mmix_operands_resume:
505 /* Just "Z", like RESUME. */
506 (*info->fprintf_func) (info->stream, "%d", z);
507 break;
508
509 default:
510 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
511 opcodep->operands);
512 break;
513 }
514
515 return 4;
516 }