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
26static void
27disassemble (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
159int
160print_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