xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/mcore-dis.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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