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