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 (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 (disassemble_info *info, 472 bfd_vma memaddr, 473 unsigned short opcode, 474 const insn_template *ptm, 475 int size) 476 { 477 print_instruction (info, memaddr, opcode, 478 ptm->name, ptm->operand_types, size, 0); 479 info->fprintf_func (info->stream, " || "); 480 return print_instruction (info, memaddr, opcode, 481 ptm->parname, ptm->paroperand_types, size, 0); 482 } 483 484 static int 485 sprint_dual_address (disassemble_info *info ATTRIBUTE_UNUSED, 486 char buf[], 487 unsigned short code) 488 { 489 const char *formats[] = { 490 "*ar%d", 491 "*ar%d-", 492 "*ar%d+", 493 "*ar%d+0%%", 494 }; 495 return sprintf (buf, formats[XMOD (code)], XARX (code)); 496 } 497 498 static int 499 sprint_indirect_address (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 (disassemble_info *info ATTRIBUTE_UNUSED, 522 char buf[], 523 unsigned short opcode) 524 { 525 /* FIXME -- look up relocation if available */ 526 return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F)); 527 } 528 529 static int 530 sprint_mmr (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 (disassemble_info *info ATTRIBUTE_UNUSED, 550 char *buf, 551 unsigned short opcode) 552 { 553 const char *cc2[] = { 554 "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq", 555 "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq", 556 }; 557 return sprintf (buf, "%s", cc2[opcode & 0xF]); 558 } 559 560 static int 561 sprint_condition (disassemble_info *info ATTRIBUTE_UNUSED, 562 char *buf, 563 unsigned short opcode) 564 { 565 char *start = buf; 566 const char *cmp[] = { 567 "??", "??", "geq", "lt", "neq", "eq", "gt", "leq" 568 }; 569 if (opcode & 0x40) 570 { 571 char acc = (opcode & 0x8) ? 'b' : 'a'; 572 if (opcode & 0x7) 573 buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)], 574 (opcode & 0x20) ? ", " : ""); 575 if (opcode & 0x20) 576 buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov"); 577 } 578 else if (opcode & 0x3F) 579 { 580 if (opcode & 0x30) 581 buf += sprintf (buf, "%s%s", 582 ((opcode & 0x30) == 0x30) ? "tc" : "ntc", 583 (opcode & 0x0F) ? ", " : ""); 584 if (opcode & 0x0C) 585 buf += sprintf (buf, "%s%s", 586 ((opcode & 0x0C) == 0x0C) ? "c" : "nc", 587 (opcode & 0x03) ? ", " : ""); 588 if (opcode & 0x03) 589 buf += sprintf (buf, "%s", 590 ((opcode & 0x03) == 0x03) ? "bio" : "nbio"); 591 } 592 else 593 buf += sprintf (buf, "unc"); 594 595 return buf - start; 596 } 597