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