1 /* Disassembly routines for TMS320C54X architecture 2 Copyright (C) 1999-2014 Free Software Foundation, Inc. 3 Contributed by Timothy Wall (twall (at) 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 "sysdep.h" 23 #include <errno.h> 24 #include <math.h> 25 #include <stdlib.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 (disassemble_info *info, 171 bfd_vma memaddr, 172 unsigned short opcode, 173 const char *tm_name, 174 const enum optype tm_operands[], 175 int size, 176 int ext) 177 { 178 static int n; 179 /* string storage for multiple operands */ 180 char operand[4][64] = { {0},{0},{0},{0}, }; 181 bfd_byte buf[2]; 182 unsigned long opcode2 = 0; 183 unsigned long lkaddr = 0; 184 enum optype src = OP_None; 185 enum optype dst = OP_None; 186 int i, shift; 187 char *comma = ""; 188 189 info->fprintf_func (info->stream, "%-7s", tm_name); 190 191 if (size > 1) 192 { 193 int status = (*info->read_memory_func) (memaddr + 1, buf, 2, info); 194 if (status != 0) 195 return 0; 196 lkaddr = opcode2 = bfd_getl16 (buf); 197 if (size > 2) 198 { 199 status = (*info->read_memory_func) (memaddr + 2, buf, 2, info); 200 if (status != 0) 201 return 0; 202 opcode2 = bfd_getl16 (buf); 203 } 204 } 205 206 for (i = 0; i < MAX_OPERANDS && OPTYPE (tm_operands[i]) != OP_None; i++) 207 { 208 char *next_comma = ","; 209 int optional = (tm_operands[i] & OPT) != 0; 210 211 switch (OPTYPE (tm_operands[i])) 212 { 213 case OP_Xmem: 214 sprint_dual_address (info, operand[i], XMEM (opcode)); 215 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 216 break; 217 case OP_Ymem: 218 sprint_dual_address (info, operand[i], YMEM (opcode)); 219 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 220 break; 221 case OP_Smem: 222 case OP_Sind: 223 case OP_Lmem: 224 info->fprintf_func (info->stream, "%s", comma); 225 if (INDIRECT (opcode)) 226 { 227 if (MOD (opcode) >= 12) 228 { 229 bfd_vma addr = lkaddr; 230 int arf = ARF (opcode); 231 int mod = MOD (opcode); 232 if (mod == 15) 233 info->fprintf_func (info->stream, "*("); 234 else 235 info->fprintf_func (info->stream, "*%sar%d(", 236 (mod == 13 || mod == 14 ? "+" : ""), 237 arf); 238 (*(info->print_address_func)) ((bfd_vma) addr, info); 239 info->fprintf_func (info->stream, ")%s", 240 mod == 14 ? "%" : ""); 241 } 242 else 243 { 244 sprint_indirect_address (info, operand[i], opcode); 245 info->fprintf_func (info->stream, "%s", operand[i]); 246 } 247 } 248 else 249 { 250 /* FIXME -- use labels (print_address_func) */ 251 /* in order to do this, we need to guess what DP is */ 252 sprint_direct_address (info, operand[i], opcode); 253 info->fprintf_func (info->stream, "%s", operand[i]); 254 } 255 break; 256 case OP_dmad: 257 info->fprintf_func (info->stream, "%s", comma); 258 (*(info->print_address_func)) ((bfd_vma) opcode2, info); 259 break; 260 case OP_xpmad: 261 /* upper 7 bits of address are in the opcode */ 262 opcode2 += ((unsigned long) opcode & 0x7F) << 16; 263 /* fall through */ 264 case OP_pmad: 265 info->fprintf_func (info->stream, "%s", comma); 266 (*(info->print_address_func)) ((bfd_vma) opcode2, info); 267 break; 268 case OP_MMRX: 269 sprint_mmr (info, operand[i], MMRX (opcode)); 270 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 271 break; 272 case OP_MMRY: 273 sprint_mmr (info, operand[i], MMRY (opcode)); 274 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 275 break; 276 case OP_MMR: 277 sprint_mmr (info, operand[i], MMR (opcode)); 278 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 279 break; 280 case OP_PA: 281 sprintf (operand[i], "pa%d", (unsigned) opcode2); 282 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 283 break; 284 case OP_SRC: 285 src = SRC (ext ? opcode2 : opcode) ? OP_B : OP_A; 286 sprintf (operand[i], (src == OP_B) ? "b" : "a"); 287 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 288 break; 289 case OP_SRC1: 290 src = SRC1 (ext ? opcode2 : opcode) ? OP_B : OP_A; 291 sprintf (operand[i], (src == OP_B) ? "b" : "a"); 292 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 293 break; 294 case OP_RND: 295 dst = DST (opcode) ? OP_B : OP_A; 296 sprintf (operand[i], (dst == OP_B) ? "a" : "b"); 297 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 298 break; 299 case OP_DST: 300 dst = DST (ext ? opcode2 : opcode) ? OP_B : OP_A; 301 if (!optional || dst != src) 302 { 303 sprintf (operand[i], (dst == OP_B) ? "b" : "a"); 304 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 305 } 306 else 307 next_comma = comma; 308 break; 309 case OP_B: 310 sprintf (operand[i], "b"); 311 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 312 break; 313 case OP_A: 314 sprintf (operand[i], "a"); 315 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 316 break; 317 case OP_ARX: 318 sprintf (operand[i], "ar%d", (int) ARX (opcode)); 319 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 320 break; 321 case OP_SHIFT: 322 shift = SHIFT (ext ? opcode2 : opcode); 323 if (!optional || shift != 0) 324 { 325 sprintf (operand[i], "%d", shift); 326 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 327 } 328 else 329 next_comma = comma; 330 break; 331 case OP_SHFT: 332 shift = SHFT (opcode); 333 if (!optional || shift != 0) 334 { 335 sprintf (operand[i], "%d", (unsigned) shift); 336 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 337 } 338 else 339 next_comma = comma; 340 break; 341 case OP_lk: 342 sprintf (operand[i], "#%d", (int) (short) opcode2); 343 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 344 break; 345 case OP_T: 346 sprintf (operand[i], "t"); 347 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 348 break; 349 case OP_TS: 350 sprintf (operand[i], "ts"); 351 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 352 break; 353 case OP_k8: 354 sprintf (operand[i], "%d", (int) ((signed char) (opcode & 0xFF))); 355 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 356 break; 357 case OP_16: 358 sprintf (operand[i], "16"); 359 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 360 break; 361 case OP_ASM: 362 sprintf (operand[i], "asm"); 363 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 364 break; 365 case OP_BITC: 366 sprintf (operand[i], "%d", (int) (opcode & 0xF)); 367 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 368 break; 369 case OP_CC: 370 /* put all CC operands in the same operand */ 371 sprint_condition (info, operand[i], opcode); 372 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 373 i = MAX_OPERANDS; 374 break; 375 case OP_CC2: 376 sprint_cc2 (info, operand[i], opcode); 377 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 378 break; 379 case OP_CC3: 380 { 381 const char *code[] = { "eq", "lt", "gt", "neq" }; 382 383 /* Do not use sprintf with only two parameters as a 384 compiler warning could be generated in such conditions. */ 385 sprintf (operand[i], "%s", code[CC3 (opcode)]); 386 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 387 break; 388 } 389 case OP_123: 390 { 391 int code = (opcode >> 8) & 0x3; 392 sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3); 393 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 394 break; 395 } 396 case OP_k5: 397 sprintf (operand[i], "#%d", 398 (int) (((signed char) opcode & 0x1F) << 3) >> 3); 399 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 400 break; 401 case OP_k8u: 402 sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF)); 403 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 404 break; 405 case OP_k3: 406 sprintf (operand[i], "#%d", (int) (opcode & 0x7)); 407 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 408 break; 409 case OP_lku: 410 sprintf (operand[i], "#%d", (unsigned) opcode2); 411 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 412 break; 413 case OP_N: 414 n = (opcode >> 9) & 0x1; 415 sprintf (operand[i], "st%d", n); 416 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 417 break; 418 case OP_SBIT: 419 { 420 const char *status0[] = { 421 "0", "1", "2", "3", "4", "5", "6", "7", "8", 422 "ovb", "ova", "c", "tc", "13", "14", "15" 423 }; 424 const char *status1[] = { 425 "0", "1", "2", "3", "4", 426 "cmpt", "frct", "c16", "sxm", "ovm", "10", 427 "intm", "hm", "xf", "cpl", "braf" 428 }; 429 sprintf (operand[i], "%s", 430 n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]); 431 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 432 break; 433 } 434 case OP_12: 435 sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1); 436 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 437 break; 438 case OP_TRN: 439 sprintf (operand[i], "trn"); 440 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 441 break; 442 case OP_DP: 443 sprintf (operand[i], "dp"); 444 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 445 break; 446 case OP_k9: 447 /* FIXME-- this is DP, print the original address? */ 448 sprintf (operand[i], "#%d", (int) (opcode & 0x1FF)); 449 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 450 break; 451 case OP_ARP: 452 sprintf (operand[i], "arp"); 453 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 454 break; 455 case OP_031: 456 sprintf (operand[i], "%d", (int) (opcode & 0x1F)); 457 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 458 break; 459 default: 460 sprintf (operand[i], "??? (0x%x)", tm_operands[i]); 461 info->fprintf_func (info->stream, "%s%s", comma, operand[i]); 462 break; 463 } 464 comma = next_comma; 465 } 466 return 1; 467 } 468 469 static int 470 print_parallel_instruction (disassemble_info *info, 471 bfd_vma memaddr, 472 unsigned short opcode, 473 const insn_template *ptm, 474 int size) 475 { 476 print_instruction (info, memaddr, opcode, 477 ptm->name, ptm->operand_types, size, 0); 478 info->fprintf_func (info->stream, " || "); 479 return print_instruction (info, memaddr, opcode, 480 ptm->parname, ptm->paroperand_types, size, 0); 481 } 482 483 static int 484 sprint_dual_address (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 (disassemble_info *info ATTRIBUTE_UNUSED, 499 char buf[], 500 unsigned short opcode) 501 { 502 const char *formats[] = { 503 "*ar%d", 504 "*ar%d-", 505 "*ar%d+", 506 "*+ar%d", 507 "*ar%d-0B", 508 "*ar%d-0", 509 "*ar%d+0", 510 "*ar%d+0B", 511 "*ar%d-%%", 512 "*ar%d-0%%", 513 "*ar%d+%%", 514 "*ar%d+0%%", 515 }; 516 return sprintf (buf, formats[MOD (opcode)], ARF (opcode)); 517 } 518 519 static int 520 sprint_direct_address (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 (disassemble_info *info ATTRIBUTE_UNUSED, 530 char buf[], 531 int mmr) 532 { 533 symbol *reg = (symbol *) mmregs; 534 while (reg->name != NULL) 535 { 536 if (mmr == reg->value) 537 { 538 sprintf (buf, "%s", (reg + 1)->name); 539 return 1; 540 } 541 ++reg; 542 } 543 sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets. */ 544 return 0; 545 } 546 547 static int 548 sprint_cc2 (disassemble_info *info ATTRIBUTE_UNUSED, 549 char *buf, 550 unsigned short opcode) 551 { 552 const char *cc2[] = { 553 "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq", 554 "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq", 555 }; 556 return sprintf (buf, "%s", cc2[opcode & 0xF]); 557 } 558 559 static int 560 sprint_condition (disassemble_info *info ATTRIBUTE_UNUSED, 561 char *buf, 562 unsigned short opcode) 563 { 564 char *start = buf; 565 const char *cmp[] = { 566 "??", "??", "geq", "lt", "neq", "eq", "gt", "leq" 567 }; 568 if (opcode & 0x40) 569 { 570 char acc = (opcode & 0x8) ? 'b' : 'a'; 571 if (opcode & 0x7) 572 buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)], 573 (opcode & 0x20) ? ", " : ""); 574 if (opcode & 0x20) 575 buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov"); 576 } 577 else if (opcode & 0x3F) 578 { 579 if (opcode & 0x30) 580 buf += sprintf (buf, "%s%s", 581 ((opcode & 0x30) == 0x30) ? "tc" : "ntc", 582 (opcode & 0x0F) ? ", " : ""); 583 if (opcode & 0x0C) 584 buf += sprintf (buf, "%s%s", 585 ((opcode & 0x0C) == 0x0C) ? "c" : "nc", 586 (opcode & 0x03) ? ", " : ""); 587 if (opcode & 0x03) 588 buf += sprintf (buf, "%s", 589 ((opcode & 0x03) == 0x03) ? "bio" : "nbio"); 590 } 591 else 592 buf += sprintf (buf, "unc"); 593 594 return buf - start; 595 } 596