This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / opcodes / m88k-dis.c
1 /* Print instructions for the Motorola 88000, for GDB and GNU Binutils.
2    Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1993
3    Free Software Foundation, Inc.
4    Contributed by Data General Corporation, November 1989.
5    Partially derived from an earlier printcmd.c.
6
7 This file is part of GDB and the GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23 #include "dis-asm.h"
24 #include "opcode/m88k.h"
25
26 /* FIXME: Uses the internal bfd swapping routines.  */
27 #include "libbfd.h"
28
29 INSTAB  *hashtable[HASHVAL] = {0};
30
31 static int
32 m88kdis PARAMS ((bfd_vma, unsigned long, struct disassemble_info *));
33
34 static void
35 printop PARAMS ((struct disassemble_info *, OPSPEC *,
36                  unsigned long, bfd_vma, int));
37
38 static void
39 init_disasm PARAMS ((void));
40
41 static void
42 install PARAMS ((INSTAB *instptr));
43
44 /*
45 *               Disassemble an M88000 Instruction
46 *
47 *
48 *       This module decodes the instruction at memaddr.
49 *
50 *                       Revision History
51 *
52 *       Revision 1.0    11/08/85        Creation date by Motorola
53 *                       05/11/89        R. Trawick adapted to GDB interface.
54 *                       07/12/93        Ian Lance Taylor updated to
55 *                                       binutils interface.
56 */
57
58 int
59 print_insn_m88k (memaddr, info)
60      bfd_vma memaddr;
61      struct disassemble_info *info;
62 {
63   bfd_byte buffer[4];
64   int status;
65
66   /* Instruction addresses may have low two bits set. Clear them.       */
67   memaddr &=~ (bfd_vma) 3;
68
69   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
70   if (status != 0)
71     {
72       (*info->memory_error_func) (status, memaddr, info);
73       return -1;
74     }
75
76   return m88kdis (memaddr, _do_getb32 (buffer), info);
77 }
78
79 /*
80  * disassemble the instruction in 'instruction'.
81  * 'pc' should be the address of this instruction, it will
82  *   be used to print the target address if this is a relative jump or call
83  * the disassembled instruction is written to 'info'.
84  * The function returns the length of this instruction in bytes.
85  */
86
87 static int
88 m88kdis (pc, instruction, info)
89      bfd_vma pc;
90      unsigned long instruction;
91      struct disassemble_info *info;
92 {
93   static int ihashtab_initialized = 0;
94   unsigned int opcode;
95   INSTAB *entry_ptr;
96   int opmask;
97   int class;
98
99   if (! ihashtab_initialized)
100     init_disasm ();
101
102   /* create a the appropriate mask to isolate the opcode */
103   opmask = DEFMASK;
104   class = instruction & DEFMASK;
105   if ((class >= SFU0) && (class <= SFU7))
106     {
107       if (instruction < SFU1)
108         opmask = CTRLMASK;
109       else
110         opmask = SFUMASK;
111     }
112   else if (class == RRR)
113     opmask = RRRMASK;
114   else if (class == RRI10)
115     opmask = RRI10MASK;
116
117   /* isolate the opcode */
118   opcode = instruction & opmask;
119
120   /* search the hash table with the isolated opcode */
121   for (entry_ptr = hashtable[opcode % HASHVAL];
122        (entry_ptr != NULL) && (entry_ptr->opcode != opcode);
123        entry_ptr = entry_ptr->next)
124     ;
125
126   if (entry_ptr == NULL)
127     (*info->fprintf_func) (info->stream, "word\t%08x", instruction);
128   else
129     {
130       (*info->fprintf_func) (info->stream, "%s ", entry_ptr->mnemonic);
131       printop (info, &(entry_ptr->op1), instruction, pc, 1);
132       printop (info, &(entry_ptr->op2), instruction, pc, 0);
133       printop (info, &(entry_ptr->op3), instruction, pc, 0);
134     }
135
136   return 4;
137 }
138 \f
139 /*
140 *                      Decode an Operand of an Instruction
141 *
142 *                       Functional Description
143 *
144 *       This module formats and writes an operand of an instruction to info
145 *       based on the operand specification.  When the first flag is set this
146 *       is the first operand of an instruction.  Undefined operand types
147 *       cause a <dis error> message.
148 *
149 *                       Parameters
150 *       disassemble_info        where the operand may be printed
151 *       OPSPEC  *opptr          Pointer to an operand specification
152 *       UINT    inst            Instruction from which operand is extracted
153 *       UINT    pc              PC of instruction; used for pc-relative disp.
154 *       int     first           Flag which if nonzero indicates the first
155 *                               operand of an instruction
156 *
157 *                       Output
158 *
159 *       The operand specified is extracted from the instruction and is
160 *       written to buf in the format specified. The operand is preceded
161 *       by a comma if it is not the first operand of an instruction and it
162 *       is not a register indirect form.  Registers are preceded by 'r' and
163 *       hex values by '0x'.
164 *
165 *                       Revision History
166 *
167 *       Revision 1.0    11/08/85        Creation date
168 */
169
170 static void
171 printop (info, opptr, inst, pc, first)
172      struct disassemble_info *info;
173      OPSPEC *opptr;
174      unsigned long inst;
175      bfd_vma pc;
176      int first;
177 {
178   int extracted_field;
179   char *cond_mask_sym;
180
181   if (opptr->width == 0)
182     return;
183
184   if (! first)
185     {
186       switch (opptr->type)
187         {
188         case REGSC:
189         case CONT:
190           break;
191         default:
192           (*info->fprintf_func) (info->stream, ",");
193           break;
194         }
195     }
196
197   switch (opptr->type)
198     {
199     case CRREG:
200       (*info->fprintf_func) (info->stream, "cr%d",
201                              UEXT (inst, opptr->offset, opptr->width));
202       break;
203
204     case FCRREG:
205       (*info->fprintf_func) (info->stream, "fcr%d",
206                              UEXT (inst, opptr->offset, opptr->width));
207       break;
208
209     case REGSC:
210       (*info->fprintf_func) (info->stream, "[r%d]",
211                              UEXT (inst, opptr->offset, opptr->width));
212       break;
213
214     case REG:
215       (*info->fprintf_func) (info->stream, "r%d",
216                              UEXT (inst, opptr->offset, opptr->width));
217       break;
218
219     case HEX:
220       extracted_field = UEXT (inst, opptr->offset, opptr->width);
221       if (extracted_field == 0)
222         (*info->fprintf_func) (info->stream, "0");
223       else
224         (*info->fprintf_func) (info->stream, "0x%02x", extracted_field);
225       break;
226
227     case CONDMASK:
228       extracted_field = UEXT (inst, opptr->offset, opptr->width);
229       switch (extracted_field & 0x0f)
230         {
231         case 0x1: cond_mask_sym = "gt0"; break;
232         case 0x2: cond_mask_sym = "eq0"; break;
233         case 0x3: cond_mask_sym = "ge0"; break;
234         case 0xc: cond_mask_sym = "lt0"; break;
235         case 0xd: cond_mask_sym = "ne0"; break;
236         case 0xe: cond_mask_sym = "le0"; break;
237         default: cond_mask_sym = NULL; break;
238         }
239       if (cond_mask_sym != NULL)
240         (*info->fprintf_func) (info->stream, "%s", cond_mask_sym);
241       else
242         (*info->fprintf_func) (info->stream, "%x", extracted_field);
243       break;
244                         
245     case PCREL:
246       (*info->print_address_func)
247         (pc + (4 * (SEXT (inst, opptr->offset, opptr->width))),
248          info);
249       break;
250
251     case CONT:
252       (*info->fprintf_func) (info->stream, "%d,r%d",
253                              UEXT (inst, opptr->offset, 5),
254                              UEXT (inst, (opptr->offset) + 5, 5));
255       break;
256
257     case BF:
258       (*info->fprintf_func) (info->stream, "%d<%d>",
259                               UEXT (inst, (opptr->offset) + 5, 5),
260                               UEXT (inst, opptr->offset, 5));
261       break;
262
263     default:
264       (*info->fprintf_func) (info->stream, "# <dis error: %08x>", inst);
265     }
266 }
267
268 /*
269 *                 Initialize the Disassembler Instruction Table
270 *
271 *       Initialize the hash table and instruction table for the disassembler.
272 *       This should be called once before the first call to disasm().
273 *
274 *                       Parameters
275 *
276 *                       Output
277 *
278 *       If the debug option is selected, certain statistics about the hashing
279 *       distribution are written to stdout.
280 *
281 *                       Revision History
282 *
283 *       Revision 1.0    11/08/85        Creation date
284 */
285
286 static void
287 init_disasm ()
288 {
289    int i, size;
290
291    for (i = 0; i < HASHVAL; i++)
292      hashtable[i] = NULL;
293
294    size = sizeof (instructions) / sizeof (INSTAB);
295    for (i = 0; i < size; i++)
296      install (&instructions[i]);
297 }
298
299 /*
300 *       Insert an instruction into the disassembler table by hashing the
301 *       opcode and inserting it into the linked list for that hash value.
302 *
303 *                       Parameters
304 *
305 *       INSTAB *instptr         Pointer to the entry in the instruction table
306 *                               to be installed
307 *
308 *       Revision 1.0    11/08/85        Creation date
309 *                       05/11/89        R. TRAWICK ADAPTED FROM MOTOROLA
310 */
311
312 static void
313 install (instptr)
314      INSTAB *instptr;
315 {
316   unsigned int i;
317
318   i = (instptr->opcode) % HASHVAL;
319   instptr->next = hashtable[i];
320   hashtable[i] = instptr;
321 }