1/* Disassemble MN10200 instructions.
2   Copyright 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, 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
26static void disassemble PARAMS ((bfd_vma, struct disassemble_info *,
27				 unsigned long insn, unsigned long,
28				 unsigned int));
29
30int
31print_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
208static void
209disassemble (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