1 /* mmix-dis.c -- Disassemble MMIX instructions. 2 Copyright 2000, 2001, 2002 Free Software Foundation, Inc. 3 Written by Hans-Peter Nilsson (hp@bitrange.com) 4 5 This file is part of GDB and the GNU binutils. 6 7 GDB and the GNU binutils are free software; you can redistribute 8 them and/or modify them under the terms of the GNU General Public 9 License as published by the Free Software Foundation; either version 2, 10 or (at your option) any later version. 11 12 GDB and the GNU binutils are distributed in the hope that they 13 will be useful, but WITHOUT ANY WARRANTY; without even the implied 14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 the GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this file; see the file COPYING. If not, write to the Free 19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include <stdio.h> 23 #include <string.h> 24 #include <stdlib.h> 25 #include "opcode/mmix.h" 26 #include "dis-asm.h" 27 #include "libiberty.h" 28 #include "bfd.h" 29 #include "opintl.h" 30 31 #define BAD_CASE(x) \ 32 do \ 33 { \ 34 fprintf (stderr, \ 35 _("Bad case %d (%s) in %s:%d\n"), \ 36 x, #x, __FILE__, __LINE__); \ 37 abort (); \ 38 } \ 39 while (0) 40 41 #define FATAL_DEBUG \ 42 do \ 43 { \ 44 fprintf (stderr, \ 45 _("Internal: Non-debugged code (test-case missing): %s:%d"),\ 46 __FILE__, __LINE__); \ 47 abort (); \ 48 } \ 49 while (0) 50 51 #define ROUND_MODE(n) \ 52 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \ 53 (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \ 54 _("(unknown)")) 55 56 #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24) 57 #define INSN_BACKWARD_OFFSET_BIT (1 << 24) 58 59 struct mmix_dis_info 60 { 61 const char *reg_name[256]; 62 const char *spec_reg_name[32]; 63 64 /* Waste a little memory so we don't have to allocate each separately. 65 We could have an array with static contents for these, but on the 66 other hand, we don't have to. */ 67 char basic_reg_name[256][sizeof ("$255")]; 68 }; 69 70 /* Initialize a target-specific array in INFO. */ 71 72 static bfd_boolean 73 initialize_mmix_dis_info (struct disassemble_info *info) 74 { 75 struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info)); 76 int i; 77 78 if (minfop == NULL) 79 return FALSE; 80 81 memset (minfop, 0, sizeof (*minfop)); 82 83 /* Initialize register names from register symbols. If there's no 84 register section, then there are no register symbols. */ 85 if ((info->section != NULL && info->section->owner != NULL) 86 || (info->symbols != NULL 87 && info->symbols[0] != NULL 88 && bfd_asymbol_bfd (info->symbols[0]) != NULL)) 89 { 90 bfd *abfd = info->section && info->section->owner != NULL 91 ? info->section->owner 92 : bfd_asymbol_bfd (info->symbols[0]); 93 asection *reg_section = bfd_get_section_by_name (abfd, "*REG*"); 94 95 if (reg_section != NULL) 96 { 97 /* The returned symcount *does* include the ending NULL. */ 98 long symsize = bfd_get_symtab_upper_bound (abfd); 99 asymbol **syms = malloc (symsize); 100 long nsyms; 101 long i; 102 103 if (syms == NULL) 104 { 105 FATAL_DEBUG; 106 free (minfop); 107 return FALSE; 108 } 109 nsyms = bfd_canonicalize_symtab (abfd, syms); 110 111 /* We use the first name for a register. If this is MMO, then 112 it's the name with the first sequence number, presumably the 113 first in the source. */ 114 for (i = 0; i < nsyms && syms[i] != NULL; i++) 115 { 116 if (syms[i]->section == reg_section 117 && syms[i]->value < 256 118 && minfop->reg_name[syms[i]->value] == NULL) 119 minfop->reg_name[syms[i]->value] = syms[i]->name; 120 } 121 } 122 } 123 124 /* Fill in the rest with the canonical names. */ 125 for (i = 0; i < 256; i++) 126 if (minfop->reg_name[i] == NULL) 127 { 128 sprintf (minfop->basic_reg_name[i], "$%d", i); 129 minfop->reg_name[i] = minfop->basic_reg_name[i]; 130 } 131 132 /* We assume it's actually a one-to-one mapping of number-to-name. */ 133 for (i = 0; mmix_spec_regs[i].name != NULL; i++) 134 minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name; 135 136 info->private_data = (void *) minfop; 137 return TRUE; 138 } 139 140 /* A table indexed by the first byte is constructed as we disassemble each 141 tetrabyte. The contents is a pointer into mmix_insns reflecting the 142 first found entry with matching match-bits and lose-bits. Further 143 entries are considered one after one until the operand constraints 144 match or the match-bits and lose-bits do not match. Normally a 145 "further entry" will just show that there was no other match. */ 146 147 static const struct mmix_opcode * 148 get_opcode (unsigned long insn) 149 { 150 static const struct mmix_opcode **opcodes = NULL; 151 const struct mmix_opcode *opcodep = mmix_opcodes; 152 unsigned int opcode_part = (insn >> 24) & 255; 153 154 if (opcodes == NULL) 155 opcodes = xcalloc (256, sizeof (struct mmix_opcode *)); 156 157 opcodep = opcodes[opcode_part]; 158 if (opcodep == NULL 159 || (opcodep->match & insn) != opcodep->match 160 || (opcodep->lose & insn) != 0) 161 { 162 /* Search through the table. */ 163 for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++) 164 { 165 /* FIXME: Break out this into an initialization function. */ 166 if ((opcodep->match & (opcode_part << 24)) == opcode_part 167 && (opcodep->lose & (opcode_part << 24)) == 0) 168 opcodes[opcode_part] = opcodep; 169 170 if ((opcodep->match & insn) == opcodep->match 171 && (opcodep->lose & insn) == 0) 172 break; 173 } 174 } 175 176 if (opcodep->name == NULL) 177 return NULL; 178 179 /* Check constraints. If they don't match, loop through the next opcode 180 entries. */ 181 do 182 { 183 switch (opcodep->operands) 184 { 185 /* These have no restraint on what can be in the lower three 186 bytes. */ 187 case mmix_operands_regs: 188 case mmix_operands_reg_yz: 189 case mmix_operands_regs_z_opt: 190 case mmix_operands_regs_z: 191 case mmix_operands_jmp: 192 case mmix_operands_pushgo: 193 case mmix_operands_pop: 194 case mmix_operands_sync: 195 case mmix_operands_x_regs_z: 196 case mmix_operands_neg: 197 case mmix_operands_pushj: 198 case mmix_operands_regaddr: 199 case mmix_operands_get: 200 case mmix_operands_set: 201 case mmix_operands_save: 202 case mmix_operands_unsave: 203 case mmix_operands_xyz_opt: 204 return opcodep; 205 206 /* For a ROUND_MODE, the middle byte must be 0..4. */ 207 case mmix_operands_roundregs_z: 208 case mmix_operands_roundregs: 209 { 210 int midbyte = (insn >> 8) & 255; 211 212 if (midbyte <= 4) 213 return opcodep; 214 } 215 break; 216 217 case mmix_operands_put: 218 /* A "PUT". If it is "immediate", then no restrictions, 219 otherwise we have to make sure the register number is < 32. */ 220 if ((insn & INSN_IMMEDIATE_BIT) 221 || ((insn >> 16) & 255) < 32) 222 return opcodep; 223 break; 224 225 case mmix_operands_resume: 226 /* Middle bytes must be zero. */ 227 if ((insn & 0x00ffff00) == 0) 228 return opcodep; 229 break; 230 231 default: 232 BAD_CASE (opcodep->operands); 233 } 234 235 opcodep++; 236 } 237 while ((opcodep->match & insn) == opcodep->match 238 && (opcodep->lose & insn) == 0); 239 240 /* If we got here, we had no match. */ 241 return NULL; 242 } 243 244 /* The main disassembly function. */ 245 246 int 247 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info) 248 { 249 unsigned char buffer[4]; 250 unsigned long insn; 251 unsigned int x, y, z; 252 const struct mmix_opcode *opcodep; 253 int status = (*info->read_memory_func) (memaddr, buffer, 4, info); 254 struct mmix_dis_info *minfop; 255 256 if (status != 0) 257 { 258 (*info->memory_error_func) (status, memaddr, info); 259 return -1; 260 } 261 262 /* FIXME: Is -1 suitable? */ 263 if (info->private_data == NULL 264 && ! initialize_mmix_dis_info (info)) 265 return -1; 266 267 minfop = (struct mmix_dis_info *) info->private_data; 268 x = buffer[1]; 269 y = buffer[2]; 270 z = buffer[3]; 271 272 insn = bfd_getb32 (buffer); 273 274 opcodep = get_opcode (insn); 275 276 if (opcodep == NULL) 277 { 278 (*info->fprintf_func) (info->stream, _("*unknown*")); 279 return 4; 280 } 281 282 (*info->fprintf_func) (info->stream, "%s ", opcodep->name); 283 284 /* Present bytes in the order they are laid out in memory. */ 285 info->display_endian = BFD_ENDIAN_BIG; 286 287 info->insn_info_valid = 1; 288 info->bytes_per_chunk = 4; 289 info->branch_delay_insns = 0; 290 info->target = 0; 291 switch (opcodep->type) 292 { 293 case mmix_type_normal: 294 case mmix_type_memaccess_block: 295 info->insn_type = dis_nonbranch; 296 break; 297 298 case mmix_type_branch: 299 info->insn_type = dis_branch; 300 break; 301 302 case mmix_type_condbranch: 303 info->insn_type = dis_condbranch; 304 break; 305 306 case mmix_type_memaccess_octa: 307 info->insn_type = dis_dref; 308 info->data_size = 8; 309 break; 310 311 case mmix_type_memaccess_tetra: 312 info->insn_type = dis_dref; 313 info->data_size = 4; 314 break; 315 316 case mmix_type_memaccess_wyde: 317 info->insn_type = dis_dref; 318 info->data_size = 2; 319 break; 320 321 case mmix_type_memaccess_byte: 322 info->insn_type = dis_dref; 323 info->data_size = 1; 324 break; 325 326 case mmix_type_jsr: 327 info->insn_type = dis_jsr; 328 break; 329 330 default: 331 BAD_CASE(opcodep->type); 332 } 333 334 switch (opcodep->operands) 335 { 336 case mmix_operands_regs: 337 /* All registers: "$X,$Y,$Z". */ 338 (*info->fprintf_func) (info->stream, "%s,%s,%s", 339 minfop->reg_name[x], 340 minfop->reg_name[y], 341 minfop->reg_name[z]); 342 break; 343 344 case mmix_operands_reg_yz: 345 /* Like SETH - "$X,YZ". */ 346 (*info->fprintf_func) (info->stream, "%s,0x%x", 347 minfop->reg_name[x], y * 256 + z); 348 break; 349 350 case mmix_operands_regs_z_opt: 351 case mmix_operands_regs_z: 352 case mmix_operands_pushgo: 353 /* The regular "$X,$Y,$Z|Z". */ 354 if (insn & INSN_IMMEDIATE_BIT) 355 (*info->fprintf_func) (info->stream, "%s,%s,%d", 356 minfop->reg_name[x], minfop->reg_name[y], z); 357 else 358 (*info->fprintf_func) (info->stream, "%s,%s,%s", 359 minfop->reg_name[x], 360 minfop->reg_name[y], 361 minfop->reg_name[z]); 362 break; 363 364 case mmix_operands_jmp: 365 /* Address; only JMP. */ 366 { 367 bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4; 368 369 if (insn & INSN_BACKWARD_OFFSET_BIT) 370 offset -= (256 * 65536) * 4; 371 372 info->target = memaddr + offset; 373 (*info->print_address_func) (memaddr + offset, info); 374 } 375 break; 376 377 case mmix_operands_roundregs_z: 378 /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z" 379 "$X,ROUND_MODE,$Z|Z". */ 380 if (y != 0) 381 { 382 if (insn & INSN_IMMEDIATE_BIT) 383 (*info->fprintf_func) (info->stream, "%s,%s,%d", 384 minfop->reg_name[x], 385 ROUND_MODE (y), z); 386 else 387 (*info->fprintf_func) (info->stream, "%s,%s,%s", 388 minfop->reg_name[x], 389 ROUND_MODE (y), 390 minfop->reg_name[z]); 391 } 392 else 393 { 394 if (insn & INSN_IMMEDIATE_BIT) 395 (*info->fprintf_func) (info->stream, "%s,%d", 396 minfop->reg_name[x], z); 397 else 398 (*info->fprintf_func) (info->stream, "%s,%s", 399 minfop->reg_name[x], 400 minfop->reg_name[z]); 401 } 402 break; 403 404 case mmix_operands_pop: 405 /* Like POP - "X,YZ". */ 406 (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z); 407 break; 408 409 case mmix_operands_roundregs: 410 /* Two registers, possibly with rounding: "$X,$Z" or 411 "$X,ROUND_MODE,$Z". */ 412 if (y != 0) 413 (*info->fprintf_func) (info->stream, "%s,%s,%s", 414 minfop->reg_name[x], 415 ROUND_MODE (y), 416 minfop->reg_name[z]); 417 else 418 (*info->fprintf_func) (info->stream, "%s,%s", 419 minfop->reg_name[x], 420 minfop->reg_name[z]); 421 break; 422 423 case mmix_operands_sync: 424 /* Like SYNC - "XYZ". */ 425 (*info->fprintf_func) (info->stream, "%u", 426 x * 65536 + y * 256 + z); 427 break; 428 429 case mmix_operands_x_regs_z: 430 /* Like SYNCD - "X,$Y,$Z|Z". */ 431 if (insn & INSN_IMMEDIATE_BIT) 432 (*info->fprintf_func) (info->stream, "%d,%s,%d", 433 x, minfop->reg_name[y], z); 434 else 435 (*info->fprintf_func) (info->stream, "%d,%s,%s", 436 x, minfop->reg_name[y], 437 minfop->reg_name[z]); 438 break; 439 440 case mmix_operands_neg: 441 /* Like NEG and NEGU - "$X,Y,$Z|Z". */ 442 if (insn & INSN_IMMEDIATE_BIT) 443 (*info->fprintf_func) (info->stream, "%s,%d,%d", 444 minfop->reg_name[x], y, z); 445 else 446 (*info->fprintf_func) (info->stream, "%s,%d,%s", 447 minfop->reg_name[x], y, 448 minfop->reg_name[z]); 449 break; 450 451 case mmix_operands_pushj: 452 case mmix_operands_regaddr: 453 /* Like GETA or branches - "$X,Address". */ 454 { 455 bfd_signed_vma offset = (y * 256 + z) * 4; 456 457 if (insn & INSN_BACKWARD_OFFSET_BIT) 458 offset -= 65536 * 4; 459 460 info->target = memaddr + offset; 461 462 (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]); 463 (*info->print_address_func) (memaddr + offset, info); 464 } 465 break; 466 467 case mmix_operands_get: 468 /* GET - "X,spec_reg". */ 469 (*info->fprintf_func) (info->stream, "%s,%s", 470 minfop->reg_name[x], 471 minfop->spec_reg_name[z]); 472 break; 473 474 case mmix_operands_put: 475 /* PUT - "spec_reg,$Z|Z". */ 476 if (insn & INSN_IMMEDIATE_BIT) 477 (*info->fprintf_func) (info->stream, "%s,%d", 478 minfop->spec_reg_name[x], z); 479 else 480 (*info->fprintf_func) (info->stream, "%s,%s", 481 minfop->spec_reg_name[x], 482 minfop->reg_name[z]); 483 break; 484 485 case mmix_operands_set: 486 /* Two registers, "$X,$Y". */ 487 (*info->fprintf_func) (info->stream, "%s,%s", 488 minfop->reg_name[x], 489 minfop->reg_name[y]); 490 break; 491 492 case mmix_operands_save: 493 /* SAVE - "$X,0". */ 494 (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]); 495 break; 496 497 case mmix_operands_unsave: 498 /* UNSAVE - "0,$Z". */ 499 (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]); 500 break; 501 502 case mmix_operands_xyz_opt: 503 /* Like SWYM or TRAP - "X,Y,Z". */ 504 (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z); 505 break; 506 507 case mmix_operands_resume: 508 /* Just "Z", like RESUME. */ 509 (*info->fprintf_func) (info->stream, "%d", z); 510 break; 511 512 default: 513 (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"), 514 opcodep->operands); 515 break; 516 } 517 518 return 4; 519 } 520