Annotation of src/external/gpl3/binutils/dist/opcodes/mmix-dis.c, Revision 1.1.1.5
1.1 skrll 1: /* mmix-dis.c -- Disassemble MMIX instructions.
1.1.1.5 ! christos 2: Copyright (C) 2000-2016 Free Software Foundation, Inc.
1.1 skrll 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:
1.1.1.3 christos 22: #include "sysdep.h"
1.1 skrll 23: #include <stdio.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:
58: struct 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:
69: /* Initialize a target-specific array in INFO. */
70:
71: static bfd_boolean
72: initialize_mmix_dis_info (struct disassemble_info *info)
73: {
74: struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
1.1.1.2 christos 75: long i;
1.1 skrll 76:
77: if (minfop == NULL)
78: return FALSE;
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;
100:
101: if (syms == NULL)
102: {
103: FATAL_DEBUG;
104: free (minfop);
105: return FALSE;
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: {
1.1.1.2 christos 126: sprintf (minfop->basic_reg_name[i], "$%ld", i);
1.1 skrll 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:
134: info->private_data = (void *) minfop;
135: return TRUE;
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:
145: static const struct mmix_opcode *
146: get_opcode (unsigned long insn)
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;
151:
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;
209:
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:
244: int
245: print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
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: }
CVSweb <webmaster@jp.NetBSD.org>