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