Release 2.33.1
[external/binutils.git] / opcodes / m10200-dis.c
1 /* Disassemble MN10200 instructions.
2    Copyright (C) 1996-2019 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
27 static void
28 disassemble (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
160 int
161 print_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 }