More changes, mostly cleanups from the last set.
[external/binutils.git] / gdb / m88k-pinsn.c
1 /* Print instructions for the Motorola 88000, for GDB and GNU Binutils.
2    Copyright 1986, 1987, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
3    Contributed by Data General Corporation, November 1989.
4    Partially derived from an earlier printcmd.c.
5
6 This file is part of GDB and the GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 #include <stdio.h>
23 #include "opcode/m88k.h"
24 #include "defs.h"
25 #include "symtab.h"
26
27 void sprint_address ();
28
29 INSTAB  *hashtable[HASHVAL] = {0};
30
31 /*
32 *               Disassemble an M88000 Instruction
33 *
34 *
35 *       This module decodes the first instruction in inbuf.  It uses the pc
36 *       to display pc-relative displacements.  It writes the disassembled
37 *       instruction in outbuf.
38 *
39 *                       Revision History
40 *
41 *       Revision 1.0    11/08/85        Creation date by Motorola
42 *                       05/11/89        R. Trawick adapted to GDB interface.
43 */
44 #define MAXLEN 20
45
46 print_insn (memaddr, stream)
47      CORE_ADDR memaddr;
48      FILE *stream;
49 {
50   unsigned char buffer[MAXLEN];
51   /* should be expanded if disassembler prints symbol names */
52   char outbuf[100];
53   int n;
54
55   /* Instruction addresses may have low two bits set. Clear them.       */
56   memaddr&= 0xfffffffc;
57   read_memory (memaddr, buffer, MAXLEN);
58
59   n = m88kdis ((int)memaddr, buffer, outbuf);
60
61   fputs (outbuf, stream);
62
63   return (n);
64 }
65
66 /*
67  * disassemble the first instruction in 'inbuf'.
68  * 'pc' should be the address of this instruction, it will
69  *   be used to print the target address if this is a relative jump or call
70  * 'outbuf' gets filled in with the disassembled instruction.  It should
71  *   be long enough to hold the longest disassembled instruction.
72  *   100 bytes is certainly enough, unless symbol printing is added later
73  * The function returns the length of this instruction in bytes.
74  */
75
76 int m88kdis( pc, inbuf, outbuf )
77
78     int         pc;
79     int         *inbuf;
80     char        *outbuf;
81
82 {   static              ihashtab_initialized = 0;
83     int                 instruction;
84     unsigned int        opcode;
85     INSTAB              *entry_ptr;
86     int                 opmask;
87     int                 class;
88
89     instruction= *inbuf;
90
91     if (!ihashtab_initialized) {
92         init_disasm();
93     }
94
95     /* create a the appropriate mask to isolate the opcode */
96     opmask= DEFMASK;
97     class= instruction & DEFMASK;
98     if ((class >= SFU0) && (class <= SFU7)) {
99         if (instruction < SFU1) {
100             opmask= CTRLMASK;
101         } else {
102             opmask= SFUMASK;
103         }
104     } else if (class == RRR) {
105         opmask= RRRMASK;
106     } else if (class == RRI10) {
107         opmask= RRI10MASK;
108     }
109
110     /* isolate the opcode */
111     opcode= instruction & opmask;
112
113     /* search the hash table with the isolated opcode */
114     for (entry_ptr= hashtable[ opcode % HASHVAL ];
115          (entry_ptr != NULL) && (entry_ptr->opcode != opcode);
116          entry_ptr= entry_ptr->next) {
117     }
118
119     if (entry_ptr == NULL) {
120         sprintf( outbuf, "word\t%08x", instruction );
121     } else {
122         sprintf( outbuf, "%s\t", entry_ptr->mnemonic );
123         sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op1), instruction, pc, 1 );
124         sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op2), instruction, pc, 0 );
125         sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op3), instruction, pc, 0 );
126     }
127
128
129     return 4;
130 }
131 \f
132
133 /*
134 *                      Decode an Operand of an Instruction
135 *
136 *                       Functional Description
137 *
138 *       This module formats and writes an operand of an instruction to buf
139 *       based on the operand specification.  When the first flag is set this
140 *       is the first operand of an instruction.  Undefined operand types
141 *       cause a <dis error> message.
142 *
143 *                       Parameters
144 *       char    *buf            buffer where the operand may be printed
145 *       OPSPEC  *opptr          Pointer to an operand specification
146 *       UINT    inst            Instruction from which operand is extracted
147 *       UINT    pc              PC of instruction; used for pc-relative disp.
148 *       int     first           Flag which if nonzero indicates the first
149 *                               operand of an instruction
150 *
151 *                       Output
152 *
153 *       The operand specified is extracted from the instruction and is
154 *       written to buf in the format specified. The operand is preceded
155 *       by a comma if it is not the first operand of an instruction and it
156 *       is not a register indirect form.  Registers are preceded by 'r' and
157 *       hex values by '0x'.
158 *
159 *                       Revision History
160 *
161 *       Revision 1.0    11/08/85        Creation date
162 */
163
164 sprintop( buf, opptr, inst, pc, first )
165
166    char   *buf;
167    OPSPEC *opptr;
168    UINT   inst;
169    int    pc;
170    int    first;
171
172 {  int    extracted_field;
173    char   *cond_mask_sym;
174    char   cond_mask_sym_buf[6];
175
176    if (opptr->width == 0)
177       return;
178
179    switch(opptr->type) {
180       case CRREG:
181                        if (!first)
182                            *buf++= ',';
183                        sprintf( buf, "cr%d", UEXT(inst,opptr->offset,opptr->width));
184                        break;
185
186       case FCRREG:
187                        if (!first)
188                            *buf++= ',';
189                        sprintf( buf, "fcr%d", UEXT(inst,opptr->offset,opptr->width));
190                        break;
191
192       case REGSC:
193                        sprintf( buf, "[r%d]", UEXT(inst,opptr->offset,opptr->width));
194                        break;
195
196       case REG:
197                        if (!first)
198                            *buf++= ',';
199                        sprintf( buf, "r%d", UEXT(inst,opptr->offset,opptr->width));
200                        break;
201
202       case HEX:
203                         if (!first)
204                            *buf++= ',';
205                         extracted_field= UEXT(inst, opptr->offset, opptr->width);
206                         if (extracted_field == 0) {
207                             sprintf( buf, "0" );
208                         } else {
209                             sprintf( buf, "0x%02x", extracted_field );
210                         }
211                         break;
212
213       case CONDMASK:
214                         if (!first)
215                            *buf++= ',';
216                         extracted_field= UEXT(inst, opptr->offset, opptr->width);
217                         switch (extracted_field & 0x0f) {
218                           case 0x1:     cond_mask_sym= "gt0";
219                                         break;
220                           case 0x2:     cond_mask_sym= "eq0";
221                                         break;
222                           case 0x3:     cond_mask_sym= "ge0";
223                                         break;
224                           case 0xc:     cond_mask_sym= "lt0";
225                                         break;
226                           case 0xd:     cond_mask_sym= "ne0";
227                                         break;
228                           case 0xe:     cond_mask_sym= "le0";
229                                         break;
230                           default:      cond_mask_sym= cond_mask_sym_buf;
231                                         sprintf( cond_mask_sym_buf,
232                                                  "%x",
233                                                  extracted_field );
234                                         break;
235                         }
236                         strcpy( buf, cond_mask_sym );
237                         break;
238                         
239       case PCREL:
240                         if (!first)
241                            *buf++= ',';
242                         sprint_address( pc + 4*(SEXT(inst,opptr->offset,opptr->width)),
243                                         buf );
244                         break;
245
246       case CONT:
247                        sprintf( buf,
248                                 "%d,r%d",
249                                 UEXT(inst,opptr->offset,5),
250                                 UEXT(inst,(opptr->offset)+5,5) );
251                        break;
252
253       case BF:
254                        if (!first)
255                            *buf++= ',';
256                        sprintf( buf,
257                                 "%d<%d>",
258                                 UEXT(inst,(opptr->offset)+5,5),
259                                 UEXT(inst,opptr->offset,5));
260                        break;
261
262       default:
263                        sprintf( buf, "<dis error: %08x>", inst );
264     }
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 init_disasm()
287 {
288    int i,size;
289
290    for (i=0 ; i < HASHVAL ; i++)
291       hashtable[i] = NULL;
292
293    for (i=0, size =  sizeof(instructions) / sizeof(INSTAB) ; i < size ;
294        install(&instructions[i++]));
295
296 }
297
298 /*
299 *       Insert an instruction into the disassembler table by hashing the
300 *       opcode and inserting it into the linked list for that hash value.
301 *
302 *                       Parameters
303 *
304 *       INSTAB *instptr         Pointer to the entry in the instruction table
305 *                               to be installed
306 *
307 *       Revision 1.0    11/08/85        Creation date
308 *                       05/11/89        R. TRAWICK ADAPTED FROM MOTOROLA
309 */
310
311 install(instptr)
312    INSTAB *instptr;
313 {
314    UINT i;
315
316    i = (instptr->opcode) % HASHVAL;
317    instptr->next = hashtable[i];
318    hashtable[i] = instptr;
319 }
320 \f
321
322 /* adapted from print_address in printcmd by R. Trawick 5/15/89.  The two should
323    be combined.
324  */
325
326 void sprint_address (addr, buffer)
327
328      CORE_ADDR  addr;
329      char       *buffer;
330
331 {
332         register int    i;
333         struct symbol   *fs;
334         char            *name;
335         int             name_location;
336
337         sprintf ( buffer, "0x%x", addr);
338
339         fs = find_pc_function (addr);
340
341         if (!fs) {
342             i = find_pc_misc_function (addr);
343
344             if (i < 0) return;  /* If nothing comes through, don't
345                                    print anything symbolic */
346
347             name = misc_function_vector[i].name;
348             name_location = misc_function_vector[i].address;
349         } else {
350             name = fs->name;
351             name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs));
352         }
353
354         if (addr - name_location)
355             sprintf (buffer, " <%s+%d>", name, addr - name_location);
356         else
357             sprintf (buffer, " <%s>", name);
358 }