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