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