1 /* mmix-dis.c -- Disassemble MMIX instructions.
2    Copyright (C) 2000-2016 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 
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
initialize_mmix_dis_info(struct disassemble_info * info)72 initialize_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 
145 static const struct mmix_opcode *
get_opcode(unsigned long insn)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
print_insn_mmix(bfd_vma memaddr,struct disassemble_info * info)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 }
518