1 /* Disassemble MN10200 instructions.
2    Copyright (C) 1996-2016 Free Software Foundation, Inc.
3 
4    This file is part of the GNU opcodes library.
5 
6    This library is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    It is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14    License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include "opcode/mn10200.h"
24 #include "dis-asm.h"
25 #include "opintl.h"
26 
27 static void
disassemble(bfd_vma memaddr,struct disassemble_info * info,unsigned long insn,unsigned long extension,unsigned int size)28 disassemble (bfd_vma memaddr,
29 	     struct disassemble_info *info,
30 	     unsigned long insn,
31 	     unsigned long extension,
32 	     unsigned int size)
33 {
34   struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes;
35   const struct mn10200_operand *operand;
36   int match = 0;
37 
38   /* Find the opcode.  */
39   while (op->name)
40     {
41       int mysize, extra_shift;
42 
43       if (op->format == FMT_1)
44 	mysize = 1;
45       else if (op->format == FMT_2
46 	       || op->format == FMT_4)
47 	mysize = 2;
48       else if (op->format == FMT_3
49 	       || op->format == FMT_5)
50 	mysize = 3;
51       else if (op->format == FMT_6)
52 	mysize = 4;
53       else if (op->format == FMT_7)
54 	mysize = 5;
55       else
56 	abort ();
57 
58       if (op->format == FMT_2 || op->format == FMT_5)
59 	extra_shift = 8;
60       else if (op->format == FMT_3
61 	       || op->format == FMT_6
62 	       || op->format == FMT_7)
63 	extra_shift = 16;
64       else
65 	extra_shift = 0;
66 
67       if ((op->mask & insn) == op->opcode
68 	  && size == (unsigned int) mysize)
69 	{
70 	  const unsigned char *opindex_ptr;
71 	  unsigned int nocomma;
72 	  int paren = 0;
73 
74 	  match = 1;
75 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
76 
77 	  /* Now print the operands.  */
78 	  for (opindex_ptr = op->operands, nocomma = 1;
79 	       *opindex_ptr != 0;
80 	       opindex_ptr++)
81 	    {
82 	      unsigned long value;
83 
84 	      operand = &mn10200_operands[*opindex_ptr];
85 
86 	      if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0)
87 		{
88 		  value = (insn & 0xffff) << 8;
89 		  value |= extension;
90 		}
91 	      else
92 		{
93 		  value = ((insn >> (operand->shift))
94 			   & ((1L << operand->bits) - 1L));
95 		}
96 
97 	      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
98 		value = ((long)(value << (32 - operand->bits))
99 			  >> (32 - operand->bits));
100 
101 	      if (!nocomma
102 		  && (!paren
103 		      || ((operand->flags & MN10200_OPERAND_PAREN) == 0)))
104 		(*info->fprintf_func) (info->stream, ",");
105 
106 	      nocomma = 0;
107 
108 	      if ((operand->flags & MN10200_OPERAND_DREG) != 0)
109 		{
110 		  value = ((insn >> (operand->shift + extra_shift))
111 			   & ((1 << operand->bits) - 1));
112 		  (*info->fprintf_func) (info->stream, "d%ld", value);
113 		}
114 
115 	      else if ((operand->flags & MN10200_OPERAND_AREG) != 0)
116 		{
117 		  value = ((insn >> (operand->shift + extra_shift))
118 			   & ((1 << operand->bits) - 1));
119 		  (*info->fprintf_func) (info->stream, "a%ld", value);
120 		}
121 
122 	      else if ((operand->flags & MN10200_OPERAND_PSW) != 0)
123 		(*info->fprintf_func) (info->stream, "psw");
124 
125 	      else if ((operand->flags & MN10200_OPERAND_MDR) != 0)
126 		(*info->fprintf_func) (info->stream, "mdr");
127 
128 	      else if ((operand->flags & MN10200_OPERAND_PAREN) != 0)
129 		{
130 		  if (paren)
131 		    (*info->fprintf_func) (info->stream, ")");
132 		  else
133 		    {
134 		      (*info->fprintf_func) (info->stream, "(");
135 		      nocomma = 1;
136 		    }
137 		  paren = !paren;
138 		}
139 
140 	      else if ((operand->flags & MN10200_OPERAND_PCREL) != 0)
141 		(*info->print_address_func)
142 		  ((value + memaddr + mysize) & 0xffffff, info);
143 
144 	      else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0)
145 		(*info->print_address_func) (value, info);
146 
147 	      else
148 		(*info->fprintf_func) (info->stream, "%ld", value);
149 	    }
150 	  /* All done. */
151 	  break;
152 	}
153       op++;
154     }
155 
156   if (!match)
157     (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn);
158 }
159 
160 int
print_insn_mn10200(bfd_vma memaddr,struct disassemble_info * info)161 print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info)
162 {
163   int status;
164   bfd_byte buffer[4];
165   unsigned long insn;
166   unsigned long extension = 0;
167   unsigned int consume;
168 
169   /* First figure out how big the opcode is.  */
170   status = (*info->read_memory_func) (memaddr, buffer, 1, info);
171   if (status != 0)
172     {
173       (*info->memory_error_func) (status, memaddr, info);
174       return -1;
175     }
176 
177   insn = *(unsigned char *) buffer;
178 
179   /* These are one byte insns.  */
180   if ((insn & 0xf0) == 0x00
181       || (insn & 0xf0) == 0x10
182       || (insn & 0xf0) == 0x20
183       || (insn & 0xf0) == 0x30
184       || ((insn & 0xf0) == 0x80
185 	  && (insn & 0x0c) >> 2 != (insn & 0x03))
186       || (insn & 0xf0) == 0x90
187       || (insn & 0xf0) == 0xa0
188       || (insn & 0xf0) == 0xb0
189       || (insn & 0xff) == 0xeb
190       || (insn & 0xff) == 0xf6
191       || (insn & 0xff) == 0xfe
192       || (insn & 0xff) == 0xff)
193     {
194       extension = 0;
195       consume = 1;
196     }
197 
198   /* These are two byte insns.  */
199   else if ((insn & 0xf0) == 0x40
200 	   || (insn & 0xf0) == 0x50
201 	   || (insn & 0xf0) == 0x60
202 	   || (insn & 0xf0) == 0x70
203 	   || (insn & 0xf0) == 0x80
204 	   || (insn & 0xfc) == 0xd0
205 	   || (insn & 0xfc) == 0xd4
206 	   || (insn & 0xfc) == 0xd8
207 	   || (insn & 0xfc) == 0xe0
208 	   || (insn & 0xfc) == 0xe4
209 	   || (insn & 0xff) == 0xe8
210 	   || (insn & 0xff) == 0xe9
211 	   || (insn & 0xff) == 0xea
212 	   || (insn & 0xff) == 0xf0
213 	   || (insn & 0xff) == 0xf1
214 	   || (insn & 0xff) == 0xf2
215 	   || (insn & 0xff) == 0xf3)
216     {
217       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
218       if (status != 0)
219 	{
220 	  (*info->memory_error_func) (status, memaddr, info);
221 	   return -1;
222 	}
223       insn = bfd_getb16 (buffer);
224       consume = 2;
225     }
226 
227   /* These are three byte insns with a 16bit operand in little
228      endian form.  */
229   else if ((insn & 0xf0) == 0xc0
230 	   || (insn & 0xfc) == 0xdc
231 	   || (insn & 0xfc) == 0xec
232 	   || (insn & 0xff) == 0xf8
233 	   || (insn & 0xff) == 0xf9
234 	   || (insn & 0xff) == 0xfa
235 	   || (insn & 0xff) == 0xfb
236 	   || (insn & 0xff) == 0xfc
237 	   || (insn & 0xff) == 0xfd)
238     {
239       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
240       if (status != 0)
241 	{
242 	  (*info->memory_error_func) (status, memaddr, info);
243 	  return -1;
244 	}
245       insn <<= 16;
246       insn |= bfd_getl16 (buffer);
247       extension = 0;
248       consume = 3;
249     }
250   /* These are three byte insns too, but we don't have to mess with
251      endianness stuff.  */
252   else if ((insn & 0xff) == 0xf5)
253     {
254       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
255       if (status != 0)
256 	{
257 	  (*info->memory_error_func) (status, memaddr, info);
258 	  return -1;
259 	}
260       insn <<= 16;
261       insn |= bfd_getb16 (buffer);
262       extension = 0;
263       consume = 3;
264     }
265 
266   /* These are four byte insns.  */
267   else if ((insn & 0xff) == 0xf7)
268     {
269       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
270       if (status != 0)
271 	{
272 	  (*info->memory_error_func) (status, memaddr, info);
273 	  return -1;
274 	}
275       insn = bfd_getb16 (buffer);
276       insn <<= 16;
277       status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
278       if (status != 0)
279 	{
280 	  (*info->memory_error_func) (status, memaddr, info);
281 	  return -1;
282 	}
283       insn |= bfd_getl16 (buffer);
284       extension = 0;
285       consume = 4;
286     }
287 
288   /* These are five byte insns.  */
289   else if ((insn & 0xff) == 0xf4)
290     {
291       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
292       if (status != 0)
293 	{
294 	  (*info->memory_error_func) (status, memaddr, info);
295 	  return -1;
296 	}
297       insn = bfd_getb16 (buffer);
298       insn <<= 16;
299 
300       status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info);
301       if (status != 0)
302 	{
303 	  (*info->memory_error_func) (status, memaddr, info);
304 	  return -1;
305 	}
306       insn |= (*(unsigned char *)buffer << 8) & 0xff00;
307 
308       status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info);
309       if (status != 0)
310 	{
311 	  (*info->memory_error_func) (status, memaddr, info);
312 	  return -1;
313 	}
314       insn |= (*(unsigned char *)buffer) & 0xff;
315 
316       status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info);
317       if (status != 0)
318 	{
319 	  (*info->memory_error_func) (status, memaddr, info);
320 	  return -1;
321 	}
322       extension = (*(unsigned char *)buffer) & 0xff;
323       consume = 5;
324     }
325   else
326     {
327       (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn);
328       return 1;
329     }
330 
331   disassemble (memaddr, info, insn, extension, consume);
332 
333   return consume;
334 }
335