Update the address and phone number of the FSF
[external/binutils.git] / opcodes / m10200-dis.c
1 /* Disassemble MN10200 instructions.
2    Copyright 1996, 1997, 1998, 2000 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, MA 02110-1301, 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
26 static void disassemble PARAMS ((bfd_vma, struct disassemble_info *,
27                                  unsigned long insn, unsigned long,
28                                  unsigned int));
29
30 int 
31 print_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
208 static void
209 disassemble (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 }