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