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