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