1 /* Disassembly routines for TMS320C54X architecture 2 Copyright 1999, 2000, 2001 Free Software Foundation, Inc. 3 Contributed by Timothy Wall (twall@cygnus.com) 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 18 02111-1307, USA. */ 19 20 #include <errno.h> 21 #include <math.h> 22 #include <stdlib.h> 23 #include "sysdep.h" 24 #include "dis-asm.h" 25 #include "opcode/tic54x.h" 26 #include "coff/tic54x.h" 27 28 static int has_lkaddr (unsigned short, const template *); 29 static int get_insn_size (unsigned short, const template *); 30 static int print_instruction (disassemble_info *, bfd_vma, 31 unsigned short, const char *, 32 const enum optype [], int, int); 33 static int print_parallel_instruction (disassemble_info *, bfd_vma, 34 unsigned short, 35 const template *, int); 36 static int sprint_dual_address (disassemble_info *,char [], 37 unsigned short); 38 static int sprint_indirect_address (disassemble_info *,char [], 39 unsigned short); 40 static int sprint_direct_address (disassemble_info *,char [], 41 unsigned short); 42 static int sprint_mmr (disassemble_info *,char [],int); 43 static int sprint_condition (disassemble_info *,char *,unsigned short); 44 static int sprint_cc2 (disassemble_info *,char *,unsigned short); 45 46 int 47 print_insn_tic54x (bfd_vma memaddr, disassemble_info *info) 48 { 49 bfd_byte opbuf[2]; 50 unsigned short opcode; 51 int status, size; 52 const template* tm; 53 54 status = (*info->read_memory_func) (memaddr, opbuf, 2, info); 55 if (status != 0) 56 { 57 (*info->memory_error_func) (status, memaddr, info); 58 return -1; 59 } 60 61 opcode = bfd_getl16 (opbuf); 62 tm = tic54x_get_insn (info, memaddr, opcode, &size); 63 64 info->bytes_per_line = 2; 65 info->bytes_per_chunk = 2; 66 info->octets_per_byte = 2; 67 info->display_endian = BFD_ENDIAN_LITTLE; 68 69 if (tm->flags & FL_PAR) 70 { 71 if (!print_parallel_instruction (info, memaddr, opcode, tm, size)) 72 return -1; 73 } 74 else 75 { 76 if (!print_instruction (info, memaddr, opcode, 77 (char *) tm->name, 78 tm->operand_types, 79 size, (tm->flags & FL_EXT))) 80 return -1; 81 } 82 83 return size * 2; 84 } 85 86 static int 87 has_lkaddr (unsigned short memdata, const template *tm) 88 { 89 return (IS_LKADDR (memdata) 90 && (OPTYPE (tm->operand_types[0]) == OP_Smem 91 || OPTYPE (tm->operand_types[1]) == OP_Smem 92 || OPTYPE (tm->operand_types[2]) == OP_Smem 93 || OPTYPE (tm->operand_types[1]) == OP_Sind 94 || OPTYPE (tm->operand_types[0]) == OP_Lmem 95 || OPTYPE (tm->operand_types[1]) == OP_Lmem)); 96 } 97 98 /* always returns 1 (whether an insn template was found) since we provide an 99 "unknown instruction" template */ 100 const template* 101 tic54x_get_insn (disassemble_info *info, bfd_vma addr, 102 unsigned short memdata, int *size) 103 { 104 const template *tm = NULL; 105 106 for (tm = tic54x_optab; tm->name; tm++) 107 { 108 if (tm->opcode == (memdata & tm->mask)) 109 { 110 /* a few opcodes span two words */ 111 if (tm->flags & FL_EXT) 112 { 113 /* if lk addressing is used, the second half of the opcode gets 114 pushed one word later */ 115 bfd_byte opbuf[2]; 116 bfd_vma addr2 = addr + 1 + has_lkaddr (memdata, tm); 117 int status = (*info->read_memory_func) (addr2, opbuf, 2, info); 118 // FIXME handle errors 119 if (status == 0) 120 { 121 unsigned short data2 = bfd_getl16 (opbuf); 122 if (tm->opcode2 == (data2 & tm->mask2)) 123 { 124 if (size) *size = get_insn_size (memdata, tm); 125 return tm; 126 } 127 } 128 } 129 else 130 { 131 if (size) *size = get_insn_size (memdata, tm); 132 return tm; 133 } 134 } 135 } 136 for (tm = (template *) tic54x_paroptab; tm->name; tm++) 137 { 138 if (tm->opcode == (memdata & tm->mask)) 139 { 140 if (size) *size = get_insn_size (memdata, tm); 141 return tm; 142 } 143 } 144 145 if (size) *size = 1; 146 return &tic54x_unknown_opcode; 147 } 148 149 static int 150 get_insn_size (unsigned short memdata, const template *insn) 151 { 152 int size; 153 154 if (insn->flags & FL_PAR) 155 { 156 /* only non-parallel instructions support lk addressing */ 157 size = insn->words; 158 } 159 else 160 { 161 size = insn->words + has_lkaddr (memdata, insn); 162 } 163 164 return size; 165 } 166 167 int 168 print_instruction (info, memaddr, opcode, tm_name, tm_operands, size, ext) 169 disassemble_info *info; 170 bfd_vma memaddr; 171 unsigned short opcode; 172 const char *tm_name; 173 const enum optype tm_operands[]; 174 int size; 175 int ext; 176 { 177 static int n; 178 /* string storage for multiple operands */ 179 char operand[4][64] = { {0},{0},{0},{0}, }; 180 bfd_byte buf[2]; 181 unsigned long opcode2 = 0; 182 unsigned long lkaddr = 0; 183 enum optype src = OP_None; 184 enum optype dst = OP_None; 185 int i, shift; 186 char *comma = ""; 187 188 info->fprintf_func (info->stream, "%-7s", tm_name); 189 190 if (size > 1) 191 { 192 int status = (*info->read_memory_func) (memaddr + 1, buf, 2, info); 193 if (status != 0) 194 return 0; 195 lkaddr = opcode2 = bfd_getl16 (buf); 196 if (size > 2) 197 { 198 status = (*info->read_memory_func) (memaddr + 2, buf, 2, info); 199 if (status != 0) 200 return 0; 201 opcode2 = bfd_getl16 (buf); 202 } 203 } 204 205 for (i = 0; i < MAX_OPERANDS && OPTYPE (tm_operands[i]) != OP_None; i++) 206 { 207 char *next_comma = ","; 208 int optional = (tm_operands[i] & OPT) != 0; 209 210 switch (OPTYPE (tm_operands[i])) 211 { 212 case OP_Xmem: 213 sprint_dual_address (info, operand[i], XMEM (opcode)); 214 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 215 break; 216 case OP_Ymem: 217 sprint_dual_address (info, operand[i], YMEM (opcode)); 218 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 219 break; 220 case OP_Smem: 221 case OP_Sind: 222 case OP_Lmem: 223 info->fprintf_func (info->stream, "%s", comma); 224 if (INDIRECT (opcode)) 225 { 226 if (MOD (opcode) >= 12) 227 { 228 bfd_vma addr = lkaddr; 229 int arf = ARF (opcode); 230 int mod = MOD (opcode); 231 if (mod == 15) 232 info->fprintf_func (info->stream, "*("); 233 else 234 info->fprintf_func (info->stream, "*%sar%d(", 235 (mod == 13 || mod == 14 ? "+" : ""), 236 arf); 237 (*(info->print_address_func)) ((bfd_vma) addr, info); 238 info->fprintf_func (info->stream, ")%s", 239 mod == 14 ? "%" : ""); 240 } 241 else 242 { 243 sprint_indirect_address (info, operand[i], opcode); 244 info->fprintf_func (info->stream, "%s", operand[i]); 245 } 246 } 247 else 248 { 249 /* FIXME -- use labels (print_address_func) */ 250 /* in order to do this, we need to guess what DP is */ 251 sprint_direct_address (info, operand[i], opcode); 252 info->fprintf_func (info->stream, "%s", operand[i]); 253 } 254 break; 255 case OP_dmad: 256 info->fprintf_func (info->stream, "%s", comma); 257 (*(info->print_address_func)) ((bfd_vma) opcode2, info); 258 break; 259 case OP_xpmad: 260 /* upper 7 bits of address are in the opcode */ 261 opcode2 += ((unsigned long) opcode & 0x7F) << 16; 262 /* fall through */ 263 case OP_pmad: 264 info->fprintf_func (info->stream, "%s", comma); 265 (*(info->print_address_func)) ((bfd_vma) opcode2, info); 266 break; 267 case OP_MMRX: 268 sprint_mmr (info, operand[i], MMRX (opcode)); 269 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 270 break; 271 case OP_MMRY: 272 sprint_mmr (info, operand[i], MMRY (opcode)); 273 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 274 break; 275 case OP_MMR: 276 sprint_mmr (info, operand[i], MMR (opcode)); 277 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 278 break; 279 case OP_PA: 280 sprintf (operand[i], "pa%d", (unsigned) opcode2); 281 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 282 break; 283 case OP_SRC: 284 src = SRC (ext ? opcode2 : opcode) ? OP_B : OP_A; 285 sprintf (operand[i], (src == OP_B) ? "b" : "a"); 286 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 287 break; 288 case OP_SRC1: 289 src = SRC1 (ext ? opcode2 : opcode) ? OP_B : OP_A; 290 sprintf (operand[i], (src == OP_B) ? "b" : "a"); 291 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 292 break; 293 case OP_RND: 294 dst = DST (opcode) ? OP_B : OP_A; 295 sprintf (operand[i], (dst == OP_B) ? "a" : "b"); 296 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 297 break; 298 case OP_DST: 299 dst = DST (ext ? opcode2 : opcode) ? OP_B : OP_A; 300 if (!optional || dst != src) 301 { 302 sprintf (operand[i], (dst == OP_B) ? "b" : "a"); 303 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 304 } 305 else 306 next_comma = comma; 307 break; 308 case OP_B: 309 sprintf (operand[i], "b"); 310 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 311 break; 312 case OP_A: 313 sprintf (operand[i], "a"); 314 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 315 break; 316 case OP_ARX: 317 sprintf (operand[i], "ar%d", (int) ARX (opcode)); 318 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 319 break; 320 case OP_SHIFT: 321 shift = SHIFT (ext ? opcode2 : opcode); 322 if (!optional || shift != 0) 323 { 324 sprintf (operand[i], "%d", shift); 325 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 326 } 327 else 328 next_comma = comma; 329 break; 330 case OP_SHFT: 331 shift = SHFT (opcode); 332 if (!optional || shift != 0) 333 { 334 sprintf (operand[i], "%d", (unsigned) shift); 335 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 336 } 337 else 338 next_comma = comma; 339 break; 340 case OP_lk: 341 sprintf (operand[i], "#%d", (int) (short) opcode2); 342 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 343 break; 344 case OP_T: 345 sprintf (operand[i], "t"); 346 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 347 break; 348 case OP_TS: 349 sprintf (operand[i], "ts"); 350 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 351 break; 352 case OP_k8: 353 sprintf (operand[i], "%d", (int) ((signed char) (opcode & 0xFF))); 354 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 355 break; 356 case OP_16: 357 sprintf (operand[i], "16"); 358 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 359 break; 360 case OP_ASM: 361 sprintf (operand[i], "asm"); 362 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 363 break; 364 case OP_BITC: 365 sprintf (operand[i], "%d", (int) (opcode & 0xF)); 366 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 367 break; 368 case OP_CC: 369 /* put all CC operands in the same operand */ 370 sprint_condition (info, operand[i], opcode); 371 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 372 i = MAX_OPERANDS; 373 break; 374 case OP_CC2: 375 sprint_cc2 (info, operand[i], opcode); 376 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 377 break; 378 case OP_CC3: 379 { 380 const char *code[] = { "eq", "lt", "gt", "neq" }; 381 sprintf (operand[i], code[CC3 (opcode)]); 382 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 383 break; 384 } 385 case OP_123: 386 { 387 int code = (opcode >> 8) & 0x3; 388 sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3); 389 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 390 break; 391 } 392 case OP_k5: 393 sprintf (operand[i], "#%d", 394 (int) (((signed char) opcode & 0x1F) << 3) >> 3); 395 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 396 break; 397 case OP_k8u: 398 sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF)); 399 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 400 break; 401 case OP_k3: 402 sprintf (operand[i], "#%d", (int) (opcode & 0x7)); 403 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 404 break; 405 case OP_lku: 406 sprintf (operand[i], "#%d", (unsigned) opcode2); 407 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 408 break; 409 case OP_N: 410 n = (opcode >> 9) & 0x1; 411 sprintf (operand[i], "st%d", n); 412 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 413 break; 414 case OP_SBIT: 415 { 416 const char *status0[] = { 417 "0", "1", "2", "3", "4", "5", "6", "7", "8", 418 "ovb", "ova", "c", "tc", "13", "14", "15" 419 }; 420 const char *status1[] = { 421 "0", "1", "2", "3", "4", 422 "cmpt", "frct", "c16", "sxm", "ovm", "10", 423 "intm", "hm", "xf", "cpl", "braf" 424 }; 425 sprintf (operand[i], "%s", 426 n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]); 427 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 428 break; 429 } 430 case OP_12: 431 sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1); 432 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 433 break; 434 case OP_TRN: 435 sprintf (operand[i], "trn"); 436 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 437 break; 438 case OP_DP: 439 sprintf (operand[i], "dp"); 440 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 441 break; 442 case OP_k9: 443 /* FIXME-- this is DP, print the original address? */ 444 sprintf (operand[i], "#%d", (int) (opcode & 0x1FF)); 445 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 446 break; 447 case OP_ARP: 448 sprintf (operand[i], "arp"); 449 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 450 break; 451 case OP_031: 452 sprintf (operand[i], "%d", (int) (opcode & 0x1F)); 453 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 454 break; 455 default: 456 sprintf (operand[i], "??? (0x%x)", tm_operands[i]); 457 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 458 break; 459 } 460 comma = next_comma; 461 } 462 return 1; 463 } 464 465 static int 466 print_parallel_instruction (info, memaddr, opcode, ptm, size) 467 disassemble_info *info; 468 bfd_vma memaddr; 469 unsigned short opcode; 470 const template *ptm; 471 int size; 472 { 473 print_instruction (info, memaddr, opcode, 474 ptm->name, ptm->operand_types, size, 0); 475 info->fprintf_func (info->stream, " || "); 476 return print_instruction (info, memaddr, opcode, 477 ptm->parname, ptm->paroperand_types, size, 0); 478 } 479 480 static int 481 sprint_dual_address (info, buf, code) 482 disassemble_info *info ATTRIBUTE_UNUSED; 483 char buf[]; 484 unsigned short code; 485 { 486 const char *formats[] = { 487 "*ar%d", 488 "*ar%d-", 489 "*ar%d+", 490 "*ar%d+0%%", 491 }; 492 return sprintf (buf, formats[XMOD (code)], XARX (code)); 493 } 494 495 static int 496 sprint_indirect_address (info, buf, opcode) 497 disassemble_info *info ATTRIBUTE_UNUSED; 498 char buf[]; 499 unsigned short opcode; 500 { 501 const char *formats[] = { 502 "*ar%d", 503 "*ar%d-", 504 "*ar%d+", 505 "*+ar%d", 506 "*ar%d-0B", 507 "*ar%d-0", 508 "*ar%d+0", 509 "*ar%d+0B", 510 "*ar%d-%%", 511 "*ar%d-0%%", 512 "*ar%d+%%", 513 "*ar%d+0%%", 514 }; 515 return sprintf (buf, formats[MOD (opcode)], ARF (opcode)); 516 } 517 518 static int 519 sprint_direct_address (info, buf, opcode) 520 disassemble_info *info ATTRIBUTE_UNUSED; 521 char buf[]; 522 unsigned short opcode; 523 { 524 /* FIXME -- look up relocation if available */ 525 return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F)); 526 } 527 528 static int 529 sprint_mmr (info, buf, mmr) 530 disassemble_info *info ATTRIBUTE_UNUSED; 531 char buf[]; 532 int mmr; 533 { 534 symbol *reg = (symbol *) mmregs; 535 while (reg->name != NULL) 536 { 537 if (mmr == reg->value) 538 { 539 sprintf (buf, "%s", (reg + 1)->name); 540 return 1; 541 } 542 ++reg; 543 } 544 sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets. */ 545 return 0; 546 } 547 548 static int 549 sprint_cc2 (info, buf, opcode) 550 disassemble_info *info ATTRIBUTE_UNUSED; 551 char *buf; 552 unsigned short opcode; 553 { 554 const char *cc2[] = { 555 "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq", 556 "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq", 557 }; 558 return sprintf (buf, "%s", cc2[opcode & 0xF]); 559 } 560 561 static int 562 sprint_condition (info, buf, opcode) 563 disassemble_info *info ATTRIBUTE_UNUSED; 564 char *buf; 565 unsigned short opcode; 566 { 567 char *start = buf; 568 const char *cmp[] = { 569 "??", "??", "geq", "lt", "neq", "eq", "gt", "leq" 570 }; 571 if (opcode & 0x40) 572 { 573 char acc = (opcode & 0x8) ? 'b' : 'a'; 574 if (opcode & 0x7) 575 buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)], 576 (opcode & 0x20) ? ", " : ""); 577 if (opcode & 0x20) 578 buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov"); 579 } 580 else if (opcode & 0x3F) 581 { 582 if (opcode & 0x30) 583 buf += sprintf (buf, "%s%s", 584 ((opcode & 0x30) == 0x30) ? "tc" : "ntc", 585 (opcode & 0x0F) ? ", " : ""); 586 if (opcode & 0x0C) 587 buf += sprintf (buf, "%s%s", 588 ((opcode & 0x0C) == 0x0C) ? "c" : "nc", 589 (opcode & 0x03) ? ", " : ""); 590 if (opcode & 0x03) 591 buf += sprintf (buf, "%s", 592 ((opcode & 0x03) == 0x03) ? "bio" : "nbio"); 593 } 594 else 595 buf += sprintf (buf, "unc"); 596 597 return buf - start; 598 } 599