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