xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/mcore-dis.c (revision d2201f2f89f0be1a0be6f7568000ed297414a06d)
1f7cc78ecSespie /* Disassemble Motorola M*Core instructions.
2*d2201f2fSdrahn    Copyright 1993, 1999, 2000, 2002 Free Software Foundation, Inc.
3f7cc78ecSespie 
4f7cc78ecSespie This program is free software; you can redistribute it and/or modify
5f7cc78ecSespie it under the terms of the GNU General Public License as published by
6f7cc78ecSespie the Free Software Foundation; either version 2 of the License, or
7f7cc78ecSespie (at your option) any later version.
8f7cc78ecSespie 
9f7cc78ecSespie This program is distributed in the hope that it will be useful,
10f7cc78ecSespie but WITHOUT ANY WARRANTY; without even the implied warranty of
11f7cc78ecSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12f7cc78ecSespie GNU General Public License for more details.
13f7cc78ecSespie 
14f7cc78ecSespie You should have received a copy of the GNU General Public License
15f7cc78ecSespie along with this program; if not, write to the Free Software
16f7cc78ecSespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17f7cc78ecSespie 
18f7cc78ecSespie #include "sysdep.h"
19f7cc78ecSespie #include <stdio.h>
20f7cc78ecSespie #define STATIC_TABLE
21f7cc78ecSespie #define DEFINE_TABLE
22f7cc78ecSespie 
23f7cc78ecSespie #include "mcore-opc.h"
24f7cc78ecSespie #include "dis-asm.h"
25f7cc78ecSespie 
26f7cc78ecSespie /* Mask for each mcore_opclass: */
27*d2201f2fSdrahn static const unsigned short imsk[] = {
28f7cc78ecSespie     /* O0  */ 0xFFFF,
29f7cc78ecSespie     /* OT  */ 0xFFFC,
30f7cc78ecSespie     /* O1  */ 0xFFF0,
315f210c2aSfgsch     /* OC  */ 0xFE00,
32f7cc78ecSespie     /* O2  */ 0xFF00,
33f7cc78ecSespie     /* X1  */ 0xFFF0,
34f7cc78ecSespie     /* OI  */ 0xFE00,
35f7cc78ecSespie     /* OB  */ 0xFE00,
36f7cc78ecSespie 
37f7cc78ecSespie     /* OMa */ 0xFFF0,
38f7cc78ecSespie     /* SI  */ 0xFE00,
39f7cc78ecSespie     /* I7  */ 0xF800,
40f7cc78ecSespie     /* LS  */ 0xF000,
41f7cc78ecSespie     /* BR  */ 0xF800,
42f7cc78ecSespie     /* BL  */ 0xFF00,
43f7cc78ecSespie     /* LR  */ 0xF000,
44f7cc78ecSespie     /* LJ  */ 0xFF00,
45f7cc78ecSespie 
46f7cc78ecSespie     /* RM  */ 0xFFF0,
47f7cc78ecSespie     /* RQ  */ 0xFFF0,
48f7cc78ecSespie     /* JSR */ 0xFFF0,
49f7cc78ecSespie     /* JMP */ 0xFFF0,
50f7cc78ecSespie     /* OBRa*/ 0xFFF0,
51f7cc78ecSespie     /* OBRb*/ 0xFF80,
52f7cc78ecSespie     /* OBRc*/ 0xFF00,
53f7cc78ecSespie     /* OBR2*/ 0xFE00,
54f7cc78ecSespie 
55f7cc78ecSespie     /* O1R1*/ 0xFFF0,
56f7cc78ecSespie     /* OMb */ 0xFF80,
57f7cc78ecSespie     /* OMc */ 0xFF00,
58f7cc78ecSespie     /* SIa */ 0xFE00,
59f7cc78ecSespie 
60f7cc78ecSespie   /* MULSH */ 0xFF00,
61f7cc78ecSespie   /* OPSR  */ 0xFFF8,   /* psrset/psrclr */
62f7cc78ecSespie 
63f7cc78ecSespie     /* JC  */ 0,		/* JC,JU,JL don't appear in object */
64f7cc78ecSespie     /* JU  */ 0,
65f7cc78ecSespie     /* JL  */ 0,
66f7cc78ecSespie     /* RSI */ 0,
67f7cc78ecSespie     /* DO21*/ 0,
68f7cc78ecSespie     /* OB2 */ 0 		/* OB2 won't appear in object.  */
69f7cc78ecSespie };
70f7cc78ecSespie 
71*d2201f2fSdrahn static const char *grname[] = {
72f7cc78ecSespie  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
73f7cc78ecSespie  "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15"
74f7cc78ecSespie };
75f7cc78ecSespie 
76f7cc78ecSespie static const char X[] = "??";
77f7cc78ecSespie 
78*d2201f2fSdrahn static const char *crname[] = {
79f7cc78ecSespie   "psr",  "vbr", "epsr", "fpsr", "epc",  "fpc",  "ss0",  "ss1",
80f7cc78ecSespie   "ss2",  "ss3", "ss4",  "gcr",  "gsr",     X,      X,      X,
81f7cc78ecSespie      X,      X,      X,      X,      X,     X,      X,      X,
82f7cc78ecSespie      X,      X,      X,      X,      X,     X,      X,      X
83f7cc78ecSespie };
84f7cc78ecSespie 
85f7cc78ecSespie static const unsigned isiz[] = { 2, 0, 1, 0 };
86f7cc78ecSespie 
87f7cc78ecSespie int
print_insn_mcore(memaddr,info)88f7cc78ecSespie print_insn_mcore (memaddr, info)
89f7cc78ecSespie      bfd_vma memaddr;
90f7cc78ecSespie      struct disassemble_info *info;
91f7cc78ecSespie {
92f7cc78ecSespie   unsigned char ibytes[4];
93f7cc78ecSespie   fprintf_ftype fprintf = info->fprintf_func;
94f7cc78ecSespie   void *stream = info->stream;
95f7cc78ecSespie   unsigned short inst;
96*d2201f2fSdrahn   const mcore_opcode_info *op;
97f7cc78ecSespie   int status;
98f7cc78ecSespie 
99f7cc78ecSespie   info->bytes_per_chunk = 2;
100f7cc78ecSespie 
101f7cc78ecSespie   status = info->read_memory_func (memaddr, ibytes, 2, info);
102f7cc78ecSespie 
103f7cc78ecSespie   if (status != 0)
104f7cc78ecSespie     {
105f7cc78ecSespie       info->memory_error_func (status, memaddr, info);
106f7cc78ecSespie       return -1;
107f7cc78ecSespie     }
108f7cc78ecSespie 
109f7cc78ecSespie   if (info->endian == BFD_ENDIAN_BIG)
110f7cc78ecSespie     inst = (ibytes[0] << 8) | ibytes[1];
111f7cc78ecSespie   else if (info->endian == BFD_ENDIAN_LITTLE)
112f7cc78ecSespie     inst = (ibytes[1] << 8) | ibytes[0];
113f7cc78ecSespie   else
114f7cc78ecSespie     abort ();
115f7cc78ecSespie 
116f7cc78ecSespie   /* Just a linear search of the table.  */
117f7cc78ecSespie   for (op = mcore_table; op->name != 0; op++)
118f7cc78ecSespie     if (op->inst == (inst & imsk[op->opclass]))
119f7cc78ecSespie       break;
120f7cc78ecSespie 
121f7cc78ecSespie   if (op->name == 0)
122f7cc78ecSespie     fprintf (stream, ".short 0x%04x", inst);
123f7cc78ecSespie   else
124f7cc78ecSespie     {
125f7cc78ecSespie       const char *name = grname[inst & 0x0F];
126f7cc78ecSespie 
127f7cc78ecSespie       fprintf (stream, "%s", op->name);
128f7cc78ecSespie 
129f7cc78ecSespie       switch (op->opclass)
130f7cc78ecSespie 	{
131*d2201f2fSdrahn 	case O0:
132*d2201f2fSdrahn 	  break;
133*d2201f2fSdrahn 
134*d2201f2fSdrahn 	case OT:
135*d2201f2fSdrahn 	  fprintf (stream, "\t%d", inst & 0x3);
136*d2201f2fSdrahn 	  break;
137*d2201f2fSdrahn 
138f7cc78ecSespie 	case O1:
139f7cc78ecSespie 	case JMP:
140*d2201f2fSdrahn 	case JSR:
141*d2201f2fSdrahn 	  fprintf (stream, "\t%s", name);
142*d2201f2fSdrahn 	  break;
143*d2201f2fSdrahn 
144*d2201f2fSdrahn 	case OC:
145*d2201f2fSdrahn 	  fprintf (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]);
146*d2201f2fSdrahn 	  break;
147*d2201f2fSdrahn 
148*d2201f2fSdrahn 	case O1R1:
149*d2201f2fSdrahn 	  fprintf (stream, "\t%s, r1", name);
150*d2201f2fSdrahn 	  break;
151*d2201f2fSdrahn 
152f7cc78ecSespie 	case MULSH:
153*d2201f2fSdrahn 	case O2:
154*d2201f2fSdrahn 	  fprintf (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]);
155*d2201f2fSdrahn 	  break;
156*d2201f2fSdrahn 
157*d2201f2fSdrahn 	case X1:
158*d2201f2fSdrahn 	  fprintf (stream, "\tr1, %s", name);
159*d2201f2fSdrahn 	  break;
160*d2201f2fSdrahn 
161*d2201f2fSdrahn 	case OI:
162*d2201f2fSdrahn 	  fprintf (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1);
163*d2201f2fSdrahn 	  break;
164*d2201f2fSdrahn 
165*d2201f2fSdrahn 	case RM:
166*d2201f2fSdrahn 	  fprintf (stream, "\t%s-r15, (r0)", name);
167*d2201f2fSdrahn 	  break;
168*d2201f2fSdrahn 
169*d2201f2fSdrahn 	case RQ:
170*d2201f2fSdrahn 	  fprintf (stream, "\tr4-r7, (%s)", name);
171*d2201f2fSdrahn 	  break;
172*d2201f2fSdrahn 
173f7cc78ecSespie 	case OB:
174f7cc78ecSespie 	case OBRa:
175f7cc78ecSespie 	case OBRb:
176f7cc78ecSespie 	case OBRc:
177f7cc78ecSespie 	case SI:
178f7cc78ecSespie 	case SIa:
179f7cc78ecSespie 	case OMa:
180f7cc78ecSespie 	case OMb:
181*d2201f2fSdrahn 	case OMc:
182*d2201f2fSdrahn 	  fprintf (stream, "\t%s, %d", name, (inst >> 4) & 0x1F);
183*d2201f2fSdrahn 	  break;
184*d2201f2fSdrahn 
185*d2201f2fSdrahn 	case I7:
186*d2201f2fSdrahn 	  fprintf (stream, "\t%s, %d", name, (inst >> 4) & 0x7F);
187*d2201f2fSdrahn 	  break;
188*d2201f2fSdrahn 
189*d2201f2fSdrahn 	case LS:
190*d2201f2fSdrahn 	  fprintf (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF],
191f7cc78ecSespie 		   name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]);
192f7cc78ecSespie 	  break;
193f7cc78ecSespie 
194f7cc78ecSespie 	case BR:
195f7cc78ecSespie 	  {
196f7cc78ecSespie 	    long val = inst & 0x3FF;
197f7cc78ecSespie 
198f7cc78ecSespie 	    if (inst & 0x400)
199f7cc78ecSespie 	      val |= 0xFFFFFC00;
200f7cc78ecSespie 
201f7cc78ecSespie 	    fprintf (stream, "\t0x%x", memaddr + 2 + (val << 1));
202f7cc78ecSespie 
203f7cc78ecSespie 	    if (strcmp (op->name, "bsr") == 0)
204f7cc78ecSespie 	      {
2055f210c2aSfgsch 		/* For bsr, we'll try to get a symbol for the target.  */
206f7cc78ecSespie 		val = memaddr + 2 + (val << 1);
207f7cc78ecSespie 
208f7cc78ecSespie 		if (info->print_address_func && val != 0)
209f7cc78ecSespie 		  {
210f7cc78ecSespie 		    fprintf (stream, "\t// ");
211f7cc78ecSespie 		    info->print_address_func (val, info);
212f7cc78ecSespie 		  }
213f7cc78ecSespie 	      }
214f7cc78ecSespie 	  }
215f7cc78ecSespie 	  break;
216f7cc78ecSespie 
217f7cc78ecSespie 	case BL:
218f7cc78ecSespie 	  {
219f7cc78ecSespie 	    long val;
220f7cc78ecSespie 	    val = (inst & 0x000F);
221f7cc78ecSespie 	    fprintf (stream, "\t%s, 0x%x",
222f7cc78ecSespie 		     grname[(inst >> 4) & 0xF], memaddr - (val << 1));
223f7cc78ecSespie 	  }
224f7cc78ecSespie 	  break;
225f7cc78ecSespie 
226f7cc78ecSespie 	case LR:
227f7cc78ecSespie 	  {
228f7cc78ecSespie 	    unsigned long val;
229f7cc78ecSespie 
230f7cc78ecSespie 	    val = (memaddr + 2 + ((inst & 0xFF) << 2)) & 0xFFFFFFFC;
231f7cc78ecSespie 
232f7cc78ecSespie 	    status = info->read_memory_func (val, ibytes, 4, info);
233f7cc78ecSespie 	    if (status != 0)
234f7cc78ecSespie 	      {
235f7cc78ecSespie 		info->memory_error_func (status, memaddr, info);
236f7cc78ecSespie 		break;
237f7cc78ecSespie 	      }
238f7cc78ecSespie 
239f7cc78ecSespie 	    if (info->endian == BFD_ENDIAN_LITTLE)
240f7cc78ecSespie 	      val = (ibytes[3] << 24) | (ibytes[2] << 16)
241f7cc78ecSespie 		| (ibytes[1] << 8) | (ibytes[0]);
242f7cc78ecSespie 	    else
243f7cc78ecSespie 	      val = (ibytes[0] << 24) | (ibytes[1] << 16)
244f7cc78ecSespie 		| (ibytes[2] << 8) | (ibytes[3]);
245f7cc78ecSespie 
246f7cc78ecSespie 	    /* Removed [] around literal value to match ABI syntax 12/95.  */
247f7cc78ecSespie 	    fprintf (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val);
248f7cc78ecSespie 
249f7cc78ecSespie 	    if (val == 0)
250f7cc78ecSespie 	      fprintf (stream, "\t// from address pool at 0x%x",
251f7cc78ecSespie 		       (memaddr + 2 + ((inst & 0xFF) << 2)) & 0xFFFFFFFC);
252f7cc78ecSespie 	  }
253f7cc78ecSespie 	  break;
254f7cc78ecSespie 
255f7cc78ecSespie 	case LJ:
256f7cc78ecSespie 	  {
257f7cc78ecSespie 	    unsigned long val;
258f7cc78ecSespie 
259f7cc78ecSespie 	    val = (memaddr + 2 + ((inst & 0xFF) << 2)) & 0xFFFFFFFC;
260f7cc78ecSespie 
261f7cc78ecSespie 	    status = info->read_memory_func (val, ibytes, 4, info);
262f7cc78ecSespie 	    if (status != 0)
263f7cc78ecSespie 	      {
264f7cc78ecSespie 		info->memory_error_func (status, memaddr, info);
265f7cc78ecSespie 		break;
266f7cc78ecSespie 	      }
267f7cc78ecSespie 
268f7cc78ecSespie 	    if (info->endian == BFD_ENDIAN_LITTLE)
269f7cc78ecSespie 	      val = (ibytes[3] << 24) | (ibytes[2] << 16)
270f7cc78ecSespie 		| (ibytes[1] << 8) | (ibytes[0]);
271f7cc78ecSespie 	    else
272f7cc78ecSespie 	      val = (ibytes[0] << 24) | (ibytes[1] << 16)
273f7cc78ecSespie 		| (ibytes[2] << 8) | (ibytes[3]);
274f7cc78ecSespie 
275f7cc78ecSespie 	    /* Removed [] around literal value to match ABI syntax 12/95.  */
276f7cc78ecSespie 	    fprintf (stream, "\t0x%X", val);
277f7cc78ecSespie 	    /* For jmpi/jsri, we'll try to get a symbol for the target.  */
278f7cc78ecSespie 	    if (info->print_address_func && val != 0)
279f7cc78ecSespie 	      {
280f7cc78ecSespie 		fprintf (stream, "\t// ");
281f7cc78ecSespie 		info->print_address_func (val, info);
282f7cc78ecSespie 	      }
283f7cc78ecSespie 	    else
284f7cc78ecSespie 	      {
285f7cc78ecSespie 		fprintf (stream, "\t// from address pool at 0x%x",
286f7cc78ecSespie 			 (memaddr + 2 + ((inst & 0xFF) << 2)) & 0xFFFFFFFC);
287f7cc78ecSespie 	      }
288f7cc78ecSespie 	  }
289f7cc78ecSespie 	  break;
290f7cc78ecSespie 
291f7cc78ecSespie 	case OPSR:
292f7cc78ecSespie 	  {
293*d2201f2fSdrahn 	    static char *fields[] = {
294f7cc78ecSespie 	      "af", "ie",    "fe",    "fe,ie",
295f7cc78ecSespie 	      "ee", "ee,ie", "ee,fe", "ee,fe,ie"
296f7cc78ecSespie 	    };
297f7cc78ecSespie 
298f7cc78ecSespie 	    fprintf (stream, "\t%s", fields[inst & 0x7]);
299f7cc78ecSespie 	  }
300f7cc78ecSespie 	  break;
301f7cc78ecSespie 
302f7cc78ecSespie 	default:
3035f210c2aSfgsch 	  /* If the disassembler lags the instruction set.  */
304f7cc78ecSespie 	  fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst);
305f7cc78ecSespie 	  break;
306f7cc78ecSespie 	}
307f7cc78ecSespie     }
308f7cc78ecSespie 
3095f210c2aSfgsch   /* Say how many bytes we consumed.  */
310f7cc78ecSespie   return 2;
311f7cc78ecSespie }
312