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