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