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