Automatic date update in version.in
[external/binutils.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 }