1 /* Disassembly routines for TMS320C54X architecture 2 Copyright 1999, 2000, 2001, 2005, 2007, 2009 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 insn_template *); 31 static int get_insn_size (unsigned short, const insn_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 insn_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 insn_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 insn_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 insn_template* 103 tic54x_get_insn (disassemble_info *info, bfd_vma addr, 104 unsigned short memdata, int *size) 105 { 106 const insn_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 = (insn_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 insn_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 384 /* Do not use sprintf with only two parameters as a 385 compiler warning could be generated in such conditions. */ 386 sprintf (operand[i], "%s", code[CC3 (opcode)]); 387 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 388 break; 389 } 390 case OP_123: 391 { 392 int code = (opcode >> 8) & 0x3; 393 sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3); 394 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 395 break; 396 } 397 case OP_k5: 398 sprintf (operand[i], "#%d", 399 (int) (((signed char) opcode & 0x1F) << 3) >> 3); 400 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 401 break; 402 case OP_k8u: 403 sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF)); 404 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 405 break; 406 case OP_k3: 407 sprintf (operand[i], "#%d", (int) (opcode & 0x7)); 408 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 409 break; 410 case OP_lku: 411 sprintf (operand[i], "#%d", (unsigned) opcode2); 412 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 413 break; 414 case OP_N: 415 n = (opcode >> 9) & 0x1; 416 sprintf (operand[i], "st%d", n); 417 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 418 break; 419 case OP_SBIT: 420 { 421 const char *status0[] = { 422 "0", "1", "2", "3", "4", "5", "6", "7", "8", 423 "ovb", "ova", "c", "tc", "13", "14", "15" 424 }; 425 const char *status1[] = { 426 "0", "1", "2", "3", "4", 427 "cmpt", "frct", "c16", "sxm", "ovm", "10", 428 "intm", "hm", "xf", "cpl", "braf" 429 }; 430 sprintf (operand[i], "%s", 431 n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]); 432 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 433 break; 434 } 435 case OP_12: 436 sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1); 437 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 438 break; 439 case OP_TRN: 440 sprintf (operand[i], "trn"); 441 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 442 break; 443 case OP_DP: 444 sprintf (operand[i], "dp"); 445 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 446 break; 447 case OP_k9: 448 /* FIXME-- this is DP, print the original address? */ 449 sprintf (operand[i], "#%d", (int) (opcode & 0x1FF)); 450 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 451 break; 452 case OP_ARP: 453 sprintf (operand[i], "arp"); 454 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 455 break; 456 case OP_031: 457 sprintf (operand[i], "%d", (int) (opcode & 0x1F)); 458 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 459 break; 460 default: 461 sprintf (operand[i], "??? (0x%x)", tm_operands[i]); 462 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 463 break; 464 } 465 comma = next_comma; 466 } 467 return 1; 468 } 469 470 static int 471 print_parallel_instruction (info, memaddr, opcode, ptm, size) 472 disassemble_info *info; 473 bfd_vma memaddr; 474 unsigned short opcode; 475 const insn_template *ptm; 476 int size; 477 { 478 print_instruction (info, memaddr, opcode, 479 ptm->name, ptm->operand_types, size, 0); 480 info->fprintf_func (info->stream, " || "); 481 return print_instruction (info, memaddr, opcode, 482 ptm->parname, ptm->paroperand_types, size, 0); 483 } 484 485 static int 486 sprint_dual_address (info, buf, code) 487 disassemble_info *info ATTRIBUTE_UNUSED; 488 char buf[]; 489 unsigned short code; 490 { 491 const char *formats[] = { 492 "*ar%d", 493 "*ar%d-", 494 "*ar%d+", 495 "*ar%d+0%%", 496 }; 497 return sprintf (buf, formats[XMOD (code)], XARX (code)); 498 } 499 500 static int 501 sprint_indirect_address (info, buf, opcode) 502 disassemble_info *info ATTRIBUTE_UNUSED; 503 char buf[]; 504 unsigned short opcode; 505 { 506 const char *formats[] = { 507 "*ar%d", 508 "*ar%d-", 509 "*ar%d+", 510 "*+ar%d", 511 "*ar%d-0B", 512 "*ar%d-0", 513 "*ar%d+0", 514 "*ar%d+0B", 515 "*ar%d-%%", 516 "*ar%d-0%%", 517 "*ar%d+%%", 518 "*ar%d+0%%", 519 }; 520 return sprintf (buf, formats[MOD (opcode)], ARF (opcode)); 521 } 522 523 static int 524 sprint_direct_address (info, buf, opcode) 525 disassemble_info *info ATTRIBUTE_UNUSED; 526 char buf[]; 527 unsigned short opcode; 528 { 529 /* FIXME -- look up relocation if available */ 530 return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F)); 531 } 532 533 static int 534 sprint_mmr (info, buf, mmr) 535 disassemble_info *info ATTRIBUTE_UNUSED; 536 char buf[]; 537 int mmr; 538 { 539 symbol *reg = (symbol *) mmregs; 540 while (reg->name != NULL) 541 { 542 if (mmr == reg->value) 543 { 544 sprintf (buf, "%s", (reg + 1)->name); 545 return 1; 546 } 547 ++reg; 548 } 549 sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets. */ 550 return 0; 551 } 552 553 static int 554 sprint_cc2 (info, buf, opcode) 555 disassemble_info *info ATTRIBUTE_UNUSED; 556 char *buf; 557 unsigned short opcode; 558 { 559 const char *cc2[] = { 560 "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq", 561 "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq", 562 }; 563 return sprintf (buf, "%s", cc2[opcode & 0xF]); 564 } 565 566 static int 567 sprint_condition (info, buf, opcode) 568 disassemble_info *info ATTRIBUTE_UNUSED; 569 char *buf; 570 unsigned short opcode; 571 { 572 char *start = buf; 573 const char *cmp[] = { 574 "??", "??", "geq", "lt", "neq", "eq", "gt", "leq" 575 }; 576 if (opcode & 0x40) 577 { 578 char acc = (opcode & 0x8) ? 'b' : 'a'; 579 if (opcode & 0x7) 580 buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)], 581 (opcode & 0x20) ? ", " : ""); 582 if (opcode & 0x20) 583 buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov"); 584 } 585 else if (opcode & 0x3F) 586 { 587 if (opcode & 0x30) 588 buf += sprintf (buf, "%s%s", 589 ((opcode & 0x30) == 0x30) ? "tc" : "ntc", 590 (opcode & 0x0F) ? ", " : ""); 591 if (opcode & 0x0C) 592 buf += sprintf (buf, "%s%s", 593 ((opcode & 0x0C) == 0x0C) ? "c" : "nc", 594 (opcode & 0x03) ? ", " : ""); 595 if (opcode & 0x03) 596 buf += sprintf (buf, "%s", 597 ((opcode & 0x03) == 0x03) ? "bio" : "nbio"); 598 } 599 else 600 buf += sprintf (buf, "unc"); 601 602 return buf - start; 603 } 604