* ppc-opc.c (powerpc_macros): Add entries for e_extlwi to e_clrlslwi.
[deliverable/binutils-gdb.git] / opcodes / mmix-dis.c
CommitLineData
afd30973 1/* mmix-dis.c -- Disassemble MMIX instructions.
aa820537 2 Copyright 2000, 2001, 2002, 2005, 2007 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
HPN
21
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include "opcode/mmix.h"
26#include "dis-asm.h"
27#include "libiberty.h"
28#include "bfd.h"
29#include "opintl.h"
30
31#define BAD_CASE(x) \
32 do \
33 { \
34 fprintf (stderr, \
35 _("Bad case %d (%s) in %s:%d\n"), \
36 x, #x, __FILE__, __LINE__); \
37 abort (); \
38 } \
39 while (0)
40
47b0e7ad
NC
41#define FATAL_DEBUG \
42 do \
43 { \
44 fprintf (stderr, \
45 _("Internal: Non-debugged code (test-case missing): %s:%d"),\
46 __FILE__, __LINE__); \
47 abort (); \
48 } \
afd30973
HPN
49 while (0)
50
51#define ROUND_MODE(n) \
52 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \
53 (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \
54 _("(unknown)"))
55
56#define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
57#define INSN_BACKWARD_OFFSET_BIT (1 << 24)
58
59struct mmix_dis_info
60 {
61 const char *reg_name[256];
62 const char *spec_reg_name[32];
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. */
67 char basic_reg_name[256][sizeof ("$255")];
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
116 && syms[i]->value < 256
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. */
124 for (i = 0; i < 256; i++)
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
243/* The main disassembly function. */
244
245int
47b0e7ad 246print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
afd30973
HPN
247{
248 unsigned char buffer[4];
249 unsigned long insn;
250 unsigned int x, y, z;
251 const struct mmix_opcode *opcodep;
252 int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
253 struct mmix_dis_info *minfop;
254
255 if (status != 0)
256 {
257 (*info->memory_error_func) (status, memaddr, info);
258 return -1;
259 }
260
261 /* FIXME: Is -1 suitable? */
262 if (info->private_data == NULL
263 && ! initialize_mmix_dis_info (info))
264 return -1;
265
266 minfop = (struct mmix_dis_info *) info->private_data;
267 x = buffer[1];
268 y = buffer[2];
269 z = buffer[3];
270
271 insn = bfd_getb32 (buffer);
272
273 opcodep = get_opcode (insn);
274
275 if (opcodep == NULL)
276 {
277 (*info->fprintf_func) (info->stream, _("*unknown*"));
278 return 4;
279 }
280
281 (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
282
283 /* Present bytes in the order they are laid out in memory. */
284 info->display_endian = BFD_ENDIAN_BIG;
285
286 info->insn_info_valid = 1;
287 info->bytes_per_chunk = 4;
288 info->branch_delay_insns = 0;
289 info->target = 0;
290 switch (opcodep->type)
291 {
292 case mmix_type_normal:
293 case mmix_type_memaccess_block:
294 info->insn_type = dis_nonbranch;
295 break;
296
297 case mmix_type_branch:
298 info->insn_type = dis_branch;
299 break;
300
301 case mmix_type_condbranch:
302 info->insn_type = dis_condbranch;
303 break;
304
305 case mmix_type_memaccess_octa:
306 info->insn_type = dis_dref;
307 info->data_size = 8;
308 break;
309
310 case mmix_type_memaccess_tetra:
311 info->insn_type = dis_dref;
312 info->data_size = 4;
313 break;
314
315 case mmix_type_memaccess_wyde:
316 info->insn_type = dis_dref;
317 info->data_size = 2;
318 break;
319
320 case mmix_type_memaccess_byte:
321 info->insn_type = dis_dref;
322 info->data_size = 1;
323 break;
324
325 case mmix_type_jsr:
326 info->insn_type = dis_jsr;
327 break;
328
329 default:
330 BAD_CASE(opcodep->type);
331 }
332
333 switch (opcodep->operands)
334 {
335 case mmix_operands_regs:
336 /* All registers: "$X,$Y,$Z". */
337 (*info->fprintf_func) (info->stream, "%s,%s,%s",
338 minfop->reg_name[x],
339 minfop->reg_name[y],
340 minfop->reg_name[z]);
341 break;
342
343 case mmix_operands_reg_yz:
344 /* Like SETH - "$X,YZ". */
345 (*info->fprintf_func) (info->stream, "%s,0x%x",
346 minfop->reg_name[x], y * 256 + z);
347 break;
348
349 case mmix_operands_regs_z_opt:
350 case mmix_operands_regs_z:
351 case mmix_operands_pushgo:
352 /* The regular "$X,$Y,$Z|Z". */
353 if (insn & INSN_IMMEDIATE_BIT)
354 (*info->fprintf_func) (info->stream, "%s,%s,%d",
355 minfop->reg_name[x], minfop->reg_name[y], z);
356 else
357 (*info->fprintf_func) (info->stream, "%s,%s,%s",
358 minfop->reg_name[x],
359 minfop->reg_name[y],
360 minfop->reg_name[z]);
361 break;
362
363 case mmix_operands_jmp:
364 /* Address; only JMP. */
365 {
366 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
367
368 if (insn & INSN_BACKWARD_OFFSET_BIT)
369 offset -= (256 * 65536) * 4;
370
371 info->target = memaddr + offset;
372 (*info->print_address_func) (memaddr + offset, info);
373 }
374 break;
375
376 case mmix_operands_roundregs_z:
377 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
378 "$X,ROUND_MODE,$Z|Z". */
379 if (y != 0)
380 {
381 if (insn & INSN_IMMEDIATE_BIT)
382 (*info->fprintf_func) (info->stream, "%s,%s,%d",
383 minfop->reg_name[x],
384 ROUND_MODE (y), z);
385 else
386 (*info->fprintf_func) (info->stream, "%s,%s,%s",
387 minfop->reg_name[x],
388 ROUND_MODE (y),
389 minfop->reg_name[z]);
390 }
391 else
392 {
393 if (insn & INSN_IMMEDIATE_BIT)
394 (*info->fprintf_func) (info->stream, "%s,%d",
395 minfop->reg_name[x], z);
396 else
397 (*info->fprintf_func) (info->stream, "%s,%s",
398 minfop->reg_name[x],
399 minfop->reg_name[z]);
400 }
401 break;
402
403 case mmix_operands_pop:
404 /* Like POP - "X,YZ". */
405 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
406 break;
407
408 case mmix_operands_roundregs:
409 /* Two registers, possibly with rounding: "$X,$Z" or
410 "$X,ROUND_MODE,$Z". */
411 if (y != 0)
412 (*info->fprintf_func) (info->stream, "%s,%s,%s",
413 minfop->reg_name[x],
414 ROUND_MODE (y),
415 minfop->reg_name[z]);
416 else
417 (*info->fprintf_func) (info->stream, "%s,%s",
418 minfop->reg_name[x],
419 minfop->reg_name[z]);
420 break;
421
422 case mmix_operands_sync:
423 /* Like SYNC - "XYZ". */
424 (*info->fprintf_func) (info->stream, "%u",
425 x * 65536 + y * 256 + z);
426 break;
427
428 case mmix_operands_x_regs_z:
429 /* Like SYNCD - "X,$Y,$Z|Z". */
430 if (insn & INSN_IMMEDIATE_BIT)
431 (*info->fprintf_func) (info->stream, "%d,%s,%d",
432 x, minfop->reg_name[y], z);
433 else
434 (*info->fprintf_func) (info->stream, "%d,%s,%s",
435 x, minfop->reg_name[y],
436 minfop->reg_name[z]);
437 break;
438
439 case mmix_operands_neg:
440 /* Like NEG and NEGU - "$X,Y,$Z|Z". */
441 if (insn & INSN_IMMEDIATE_BIT)
442 (*info->fprintf_func) (info->stream, "%s,%d,%d",
443 minfop->reg_name[x], y, z);
444 else
445 (*info->fprintf_func) (info->stream, "%s,%d,%s",
446 minfop->reg_name[x], y,
447 minfop->reg_name[z]);
448 break;
449
450 case mmix_operands_pushj:
451 case mmix_operands_regaddr:
452 /* Like GETA or branches - "$X,Address". */
453 {
454 bfd_signed_vma offset = (y * 256 + z) * 4;
455
456 if (insn & INSN_BACKWARD_OFFSET_BIT)
457 offset -= 65536 * 4;
458
459 info->target = memaddr + offset;
460
461 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
462 (*info->print_address_func) (memaddr + offset, info);
463 }
464 break;
465
466 case mmix_operands_get:
467 /* GET - "X,spec_reg". */
468 (*info->fprintf_func) (info->stream, "%s,%s",
469 minfop->reg_name[x],
470 minfop->spec_reg_name[z]);
471 break;
472
473 case mmix_operands_put:
474 /* PUT - "spec_reg,$Z|Z". */
475 if (insn & INSN_IMMEDIATE_BIT)
476 (*info->fprintf_func) (info->stream, "%s,%d",
477 minfop->spec_reg_name[x], z);
478 else
479 (*info->fprintf_func) (info->stream, "%s,%s",
480 minfop->spec_reg_name[x],
481 minfop->reg_name[z]);
482 break;
483
484 case mmix_operands_set:
485 /* Two registers, "$X,$Y". */
486 (*info->fprintf_func) (info->stream, "%s,%s",
487 minfop->reg_name[x],
488 minfop->reg_name[y]);
489 break;
490
491 case mmix_operands_save:
492 /* SAVE - "$X,0". */
493 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
494 break;
495
496 case mmix_operands_unsave:
497 /* UNSAVE - "0,$Z". */
498 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
499 break;
500
501 case mmix_operands_xyz_opt:
502 /* Like SWYM or TRAP - "X,Y,Z". */
503 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
504 break;
505
506 case mmix_operands_resume:
507 /* Just "Z", like RESUME. */
508 (*info->fprintf_func) (info->stream, "%d", z);
509 break;
510
511 default:
512 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
513 opcodep->operands);
514 break;
515 }
516
517 return 4;
518}
This page took 0.469279 seconds and 4 git commands to generate.