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