175fd0b74Schristos /* Disassemble Motorola M*Core instructions.
2*e992f068Schristos Copyright (C) 1993-2022 Free Software Foundation, Inc.
375fd0b74Schristos
475fd0b74Schristos This file is part of the GNU opcodes library.
575fd0b74Schristos
675fd0b74Schristos This library is free software; you can redistribute it and/or modify
775fd0b74Schristos it under the terms of the GNU General Public License as published by
875fd0b74Schristos the Free Software Foundation; either version 3, or (at your option)
975fd0b74Schristos any later version.
1075fd0b74Schristos
1175fd0b74Schristos It is distributed in the hope that it will be useful, but WITHOUT
1275fd0b74Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1375fd0b74Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1475fd0b74Schristos License for more details.
1575fd0b74Schristos
1675fd0b74Schristos You should have received a copy of the GNU General Public License
1775fd0b74Schristos along with this program; if not, write to the Free Software
1875fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
1975fd0b74Schristos MA 02110-1301, USA. */
2075fd0b74Schristos
2175fd0b74Schristos #include "sysdep.h"
2275fd0b74Schristos #include <stdio.h>
2375fd0b74Schristos #include "libiberty.h"
2475fd0b74Schristos #define STATIC_TABLE
2575fd0b74Schristos #define DEFINE_TABLE
2675fd0b74Schristos
2775fd0b74Schristos #include "mcore-opc.h"
28ede78133Schristos #include "disassemble.h"
2975fd0b74Schristos
3075fd0b74Schristos /* Mask for each mcore_opclass: */
3175fd0b74Schristos static const unsigned short imsk[] = {
3275fd0b74Schristos /* O0 */ 0xFFFF,
3375fd0b74Schristos /* OT */ 0xFFFC,
3475fd0b74Schristos /* O1 */ 0xFFF0,
3575fd0b74Schristos /* OC */ 0xFE00,
3675fd0b74Schristos /* O2 */ 0xFF00,
3775fd0b74Schristos /* X1 */ 0xFFF0,
3875fd0b74Schristos /* OI */ 0xFE00,
3975fd0b74Schristos /* OB */ 0xFE00,
4075fd0b74Schristos
4175fd0b74Schristos /* OMa */ 0xFFF0,
4275fd0b74Schristos /* SI */ 0xFE00,
4375fd0b74Schristos /* I7 */ 0xF800,
4475fd0b74Schristos /* LS */ 0xF000,
4575fd0b74Schristos /* BR */ 0xF800,
4675fd0b74Schristos /* BL */ 0xFF00,
4775fd0b74Schristos /* LR */ 0xF000,
4875fd0b74Schristos /* LJ */ 0xFF00,
4975fd0b74Schristos
5075fd0b74Schristos /* RM */ 0xFFF0,
5175fd0b74Schristos /* RQ */ 0xFFF0,
5275fd0b74Schristos /* JSR */ 0xFFF0,
5375fd0b74Schristos /* JMP */ 0xFFF0,
5475fd0b74Schristos /* OBRa*/ 0xFFF0,
5575fd0b74Schristos /* OBRb*/ 0xFF80,
5675fd0b74Schristos /* OBRc*/ 0xFF00,
5775fd0b74Schristos /* OBR2*/ 0xFE00,
5875fd0b74Schristos
5975fd0b74Schristos /* O1R1*/ 0xFFF0,
6075fd0b74Schristos /* OMb */ 0xFF80,
6175fd0b74Schristos /* OMc */ 0xFF00,
6275fd0b74Schristos /* SIa */ 0xFE00,
6375fd0b74Schristos
6475fd0b74Schristos /* MULSH */ 0xFF00,
6575fd0b74Schristos /* OPSR */ 0xFFF8, /* psrset/psrclr */
6675fd0b74Schristos
6775fd0b74Schristos /* JC */ 0, /* JC,JU,JL don't appear in object */
6875fd0b74Schristos /* JU */ 0,
6975fd0b74Schristos /* JL */ 0,
7075fd0b74Schristos /* RSI */ 0,
7175fd0b74Schristos /* DO21*/ 0,
7275fd0b74Schristos /* OB2 */ 0 /* OB2 won't appear in object. */
7375fd0b74Schristos };
7475fd0b74Schristos
7575fd0b74Schristos static const char *grname[] = {
7675fd0b74Schristos "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
7775fd0b74Schristos "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
7875fd0b74Schristos };
7975fd0b74Schristos
8075fd0b74Schristos static const char X[] = "??";
8175fd0b74Schristos
8275fd0b74Schristos static const char *crname[] = {
8375fd0b74Schristos "psr", "vbr", "epsr", "fpsr", "epc", "fpc", "ss0", "ss1",
8475fd0b74Schristos "ss2", "ss3", "ss4", "gcr", "gsr", X, X, X,
8575fd0b74Schristos X, X, X, X, X, X, X, X,
8675fd0b74Schristos X, X, X, X, X, X, X, X
8775fd0b74Schristos };
8875fd0b74Schristos
8975fd0b74Schristos static const unsigned isiz[] = { 2, 0, 1, 0 };
9075fd0b74Schristos
9175fd0b74Schristos int
print_insn_mcore(bfd_vma memaddr,struct disassemble_info * info)9275fd0b74Schristos print_insn_mcore (bfd_vma memaddr,
9375fd0b74Schristos struct disassemble_info *info)
9475fd0b74Schristos {
9575fd0b74Schristos unsigned char ibytes[4];
9675fd0b74Schristos fprintf_ftype print_func = info->fprintf_func;
9775fd0b74Schristos void *stream = info->stream;
98*e992f068Schristos unsigned int inst;
9975fd0b74Schristos unsigned int i;
10075fd0b74Schristos int status;
10175fd0b74Schristos
10275fd0b74Schristos info->bytes_per_chunk = 2;
10375fd0b74Schristos
10475fd0b74Schristos status = info->read_memory_func (memaddr, ibytes, 2, info);
10575fd0b74Schristos
10675fd0b74Schristos if (status != 0)
10775fd0b74Schristos {
10875fd0b74Schristos info->memory_error_func (status, memaddr, info);
10975fd0b74Schristos return -1;
11075fd0b74Schristos }
11175fd0b74Schristos
11275fd0b74Schristos if (info->endian == BFD_ENDIAN_BIG)
11375fd0b74Schristos inst = (ibytes[0] << 8) | ibytes[1];
11475fd0b74Schristos else if (info->endian == BFD_ENDIAN_LITTLE)
11575fd0b74Schristos inst = (ibytes[1] << 8) | ibytes[0];
11675fd0b74Schristos else
11775fd0b74Schristos abort ();
11875fd0b74Schristos
11975fd0b74Schristos /* Just a linear search of the table. */
12075fd0b74Schristos for (i = 0; i < ARRAY_SIZE (mcore_table); i++)
12175fd0b74Schristos if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass]))
12275fd0b74Schristos break;
12375fd0b74Schristos
12475fd0b74Schristos if (i == ARRAY_SIZE (mcore_table))
12575fd0b74Schristos (*print_func) (stream, ".short 0x%04x", inst);
12675fd0b74Schristos else
12775fd0b74Schristos {
12875fd0b74Schristos const char *name = grname[inst & 0x0F];
12975fd0b74Schristos
13075fd0b74Schristos (*print_func) (stream, "%s", mcore_table[i].name);
13175fd0b74Schristos
13275fd0b74Schristos switch (mcore_table[i].opclass)
13375fd0b74Schristos {
13475fd0b74Schristos case O0:
13575fd0b74Schristos break;
13675fd0b74Schristos
13775fd0b74Schristos case OT:
13875fd0b74Schristos (*print_func) (stream, "\t%d", inst & 0x3);
13975fd0b74Schristos break;
14075fd0b74Schristos
14175fd0b74Schristos case O1:
14275fd0b74Schristos case JMP:
14375fd0b74Schristos case JSR:
14475fd0b74Schristos (*print_func) (stream, "\t%s", name);
14575fd0b74Schristos break;
14675fd0b74Schristos
14775fd0b74Schristos case OC:
14875fd0b74Schristos (*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]);
14975fd0b74Schristos break;
15075fd0b74Schristos
15175fd0b74Schristos case O1R1:
15275fd0b74Schristos (*print_func) (stream, "\t%s, r1", name);
15375fd0b74Schristos break;
15475fd0b74Schristos
15575fd0b74Schristos case MULSH:
15675fd0b74Schristos case O2:
15775fd0b74Schristos (*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]);
15875fd0b74Schristos break;
15975fd0b74Schristos
16075fd0b74Schristos case X1:
16175fd0b74Schristos (*print_func) (stream, "\tr1, %s", name);
16275fd0b74Schristos break;
16375fd0b74Schristos
16475fd0b74Schristos case OI:
16575fd0b74Schristos (*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1);
16675fd0b74Schristos break;
16775fd0b74Schristos
16875fd0b74Schristos case RM:
16975fd0b74Schristos (*print_func) (stream, "\t%s-r15, (r0)", name);
17075fd0b74Schristos break;
17175fd0b74Schristos
17275fd0b74Schristos case RQ:
17375fd0b74Schristos (*print_func) (stream, "\tr4-r7, (%s)", name);
17475fd0b74Schristos break;
17575fd0b74Schristos
17675fd0b74Schristos case OB:
17775fd0b74Schristos case OBRa:
17875fd0b74Schristos case OBRb:
17975fd0b74Schristos case OBRc:
18075fd0b74Schristos case SI:
18175fd0b74Schristos case SIa:
18275fd0b74Schristos case OMa:
18375fd0b74Schristos case OMb:
18475fd0b74Schristos case OMc:
18575fd0b74Schristos (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F);
18675fd0b74Schristos break;
18775fd0b74Schristos
18875fd0b74Schristos case I7:
18975fd0b74Schristos (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F);
19075fd0b74Schristos break;
19175fd0b74Schristos
19275fd0b74Schristos case LS:
19375fd0b74Schristos (*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF],
19475fd0b74Schristos name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]);
19575fd0b74Schristos break;
19675fd0b74Schristos
19775fd0b74Schristos case BR:
19875fd0b74Schristos {
199012573ebSchristos uint32_t val = ((inst & 0x3FF) ^ 0x400) - 0x400;
20075fd0b74Schristos
201012573ebSchristos val = memaddr + 2 + (val << 1);
202012573ebSchristos (*print_func) (stream, "\t0x%x", val);
20375fd0b74Schristos
20475fd0b74Schristos if (strcmp (mcore_table[i].name, "bsr") == 0)
20575fd0b74Schristos {
20675fd0b74Schristos /* For bsr, we'll try to get a symbol for the target. */
20775fd0b74Schristos if (info->print_address_func && val != 0)
20875fd0b74Schristos {
20975fd0b74Schristos (*print_func) (stream, "\t// ");
21075fd0b74Schristos info->print_address_func (val, info);
21175fd0b74Schristos }
21275fd0b74Schristos }
21375fd0b74Schristos }
21475fd0b74Schristos break;
21575fd0b74Schristos
21675fd0b74Schristos case BL:
21775fd0b74Schristos {
218*e992f068Schristos uint32_t val = memaddr + 2 + ((inst | ~0xF) << 1);
219*e992f068Schristos
220012573ebSchristos (*print_func) (stream, "\t%s, 0x%x",
221*e992f068Schristos grname[(inst >> 4) & 0xF], val);
22275fd0b74Schristos }
22375fd0b74Schristos break;
22475fd0b74Schristos
22575fd0b74Schristos case LR:
22675fd0b74Schristos {
227012573ebSchristos uint32_t val;
22875fd0b74Schristos
229012573ebSchristos val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3;
23075fd0b74Schristos
23175fd0b74Schristos /* We are not reading an instruction, so allow
23275fd0b74Schristos reads to extend beyond the next symbol. */
23375fd0b74Schristos info->stop_vma = 0;
23475fd0b74Schristos status = info->read_memory_func (val, ibytes, 4, info);
23575fd0b74Schristos if (status != 0)
23675fd0b74Schristos {
23775fd0b74Schristos info->memory_error_func (status, memaddr, info);
23875fd0b74Schristos break;
23975fd0b74Schristos }
24075fd0b74Schristos
24175fd0b74Schristos if (info->endian == BFD_ENDIAN_LITTLE)
242012573ebSchristos val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
243012573ebSchristos | (ibytes[1] << 8) | (ibytes[0]));
24475fd0b74Schristos else
245012573ebSchristos val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
246012573ebSchristos | (ibytes[2] << 8) | (ibytes[3]));
24775fd0b74Schristos
24875fd0b74Schristos /* Removed [] around literal value to match ABI syntax 12/95. */
249012573ebSchristos (*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val);
25075fd0b74Schristos
25175fd0b74Schristos if (val == 0)
252012573ebSchristos (*print_func) (stream, "\t// from address pool at 0x%x",
253012573ebSchristos (uint32_t) (memaddr + 2
254012573ebSchristos + ((inst & 0xFF) << 2)) & ~3);
25575fd0b74Schristos }
25675fd0b74Schristos break;
25775fd0b74Schristos
25875fd0b74Schristos case LJ:
25975fd0b74Schristos {
260012573ebSchristos uint32_t val;
26175fd0b74Schristos
262012573ebSchristos val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3;
26375fd0b74Schristos
26475fd0b74Schristos /* We are not reading an instruction, so allow
26575fd0b74Schristos reads to extend beyond the next symbol. */
26675fd0b74Schristos info->stop_vma = 0;
26775fd0b74Schristos status = info->read_memory_func (val, ibytes, 4, info);
26875fd0b74Schristos if (status != 0)
26975fd0b74Schristos {
27075fd0b74Schristos info->memory_error_func (status, memaddr, info);
27175fd0b74Schristos break;
27275fd0b74Schristos }
27375fd0b74Schristos
27475fd0b74Schristos if (info->endian == BFD_ENDIAN_LITTLE)
275012573ebSchristos val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
276012573ebSchristos | (ibytes[1] << 8) | (ibytes[0]));
27775fd0b74Schristos else
278012573ebSchristos val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
279012573ebSchristos | (ibytes[2] << 8) | (ibytes[3]));
28075fd0b74Schristos
28175fd0b74Schristos /* Removed [] around literal value to match ABI syntax 12/95. */
282012573ebSchristos (*print_func) (stream, "\t0x%X", val);
28375fd0b74Schristos /* For jmpi/jsri, we'll try to get a symbol for the target. */
28475fd0b74Schristos if (info->print_address_func && val != 0)
28575fd0b74Schristos {
28675fd0b74Schristos (*print_func) (stream, "\t// ");
28775fd0b74Schristos info->print_address_func (val, info);
28875fd0b74Schristos }
28975fd0b74Schristos else
29075fd0b74Schristos {
291012573ebSchristos (*print_func) (stream, "\t// from address pool at 0x%x",
292012573ebSchristos (uint32_t) (memaddr + 2
293012573ebSchristos + ((inst & 0xFF) << 2)) & ~3);
29475fd0b74Schristos }
29575fd0b74Schristos }
29675fd0b74Schristos break;
29775fd0b74Schristos
29875fd0b74Schristos case OPSR:
29975fd0b74Schristos {
30075fd0b74Schristos static char *fields[] = {
30175fd0b74Schristos "af", "ie", "fe", "fe,ie",
30275fd0b74Schristos "ee", "ee,ie", "ee,fe", "ee,fe,ie"
30375fd0b74Schristos };
30475fd0b74Schristos
30575fd0b74Schristos (*print_func) (stream, "\t%s", fields[inst & 0x7]);
30675fd0b74Schristos }
30775fd0b74Schristos break;
30875fd0b74Schristos
30975fd0b74Schristos default:
31075fd0b74Schristos /* If the disassembler lags the instruction set. */
31175fd0b74Schristos (*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst);
31275fd0b74Schristos break;
31375fd0b74Schristos }
31475fd0b74Schristos }
31575fd0b74Schristos
31675fd0b74Schristos /* Say how many bytes we consumed. */
31775fd0b74Schristos return 2;
31875fd0b74Schristos }
319