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