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