1/* mmix-dis.c -- Disassemble MMIX instructions.
2   Copyright (C) 2000-2017 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 "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
58struct 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
71static bfd_boolean
72initialize_mmix_dis_info (struct disassemble_info *info)
73{
74  struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
75  long i;
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      {
126	sprintf (minfop->basic_reg_name[i], "$%ld", i);
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
145static const struct mmix_opcode *
146get_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
244int
245print_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}
518