1 /* Disassembly routines for TMS320C30 architecture 2 Copyright 1998, 1999, 2000, 2002, 2005, 2007, 2009, 2012 3 Free Software Foundation, Inc. 4 Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) 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 "dis-asm.h" 27 #include "opcode/tic30.h" 28 29 #define NORMAL_INSN 1 30 #define PARALLEL_INSN 2 31 32 /* Gets the type of instruction based on the top 2 or 3 bits of the 33 instruction word. */ 34 #define GET_TYPE(insn) (insn & 0x80000000 ? insn & 0xC0000000 : insn & 0xE0000000) 35 36 /* Instruction types. */ 37 #define TWO_OPERAND_1 0x00000000 38 #define TWO_OPERAND_2 0x40000000 39 #define THREE_OPERAND 0x20000000 40 #define PAR_STORE 0xC0000000 41 #define MUL_ADDS 0x80000000 42 #define BRANCHES 0x60000000 43 44 /* Specific instruction id bits. */ 45 #define NORMAL_IDEN 0x1F800000 46 #define PAR_STORE_IDEN 0x3E000000 47 #define MUL_ADD_IDEN 0x2C000000 48 #define BR_IMM_IDEN 0x1F000000 49 #define BR_COND_IDEN 0x1C3F0000 50 51 /* Addressing modes. */ 52 #define AM_REGISTER 0x00000000 53 #define AM_DIRECT 0x00200000 54 #define AM_INDIRECT 0x00400000 55 #define AM_IMM 0x00600000 56 57 #define P_FIELD 0x03000000 58 59 #define REG_AR0 0x08 60 #define LDP_INSN 0x08700000 61 62 /* TMS320C30 program counter for current instruction. */ 63 static unsigned int _pc; 64 65 struct instruction 66 { 67 int type; 68 insn_template *tm; 69 partemplate *ptm; 70 }; 71 72 static int 73 get_tic30_instruction (unsigned long insn_word, struct instruction *insn) 74 { 75 switch (GET_TYPE (insn_word)) 76 { 77 case TWO_OPERAND_1: 78 case TWO_OPERAND_2: 79 case THREE_OPERAND: 80 insn->type = NORMAL_INSN; 81 { 82 insn_template *current_optab = (insn_template *) tic30_optab; 83 84 for (; current_optab < tic30_optab_end; current_optab++) 85 { 86 if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word)) 87 { 88 if (current_optab->operands == 0) 89 { 90 if (current_optab->base_opcode == insn_word) 91 { 92 insn->tm = current_optab; 93 break; 94 } 95 } 96 else if ((current_optab->base_opcode & NORMAL_IDEN) == (insn_word & NORMAL_IDEN)) 97 { 98 insn->tm = current_optab; 99 break; 100 } 101 } 102 } 103 } 104 break; 105 106 case PAR_STORE: 107 insn->type = PARALLEL_INSN; 108 { 109 partemplate *current_optab = (partemplate *) tic30_paroptab; 110 111 for (; current_optab < tic30_paroptab_end; current_optab++) 112 { 113 if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word)) 114 { 115 if ((current_optab->base_opcode & PAR_STORE_IDEN) 116 == (insn_word & PAR_STORE_IDEN)) 117 { 118 insn->ptm = current_optab; 119 break; 120 } 121 } 122 } 123 } 124 break; 125 126 case MUL_ADDS: 127 insn->type = PARALLEL_INSN; 128 { 129 partemplate *current_optab = (partemplate *) tic30_paroptab; 130 131 for (; current_optab < tic30_paroptab_end; current_optab++) 132 { 133 if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word)) 134 { 135 if ((current_optab->base_opcode & MUL_ADD_IDEN) 136 == (insn_word & MUL_ADD_IDEN)) 137 { 138 insn->ptm = current_optab; 139 break; 140 } 141 } 142 } 143 } 144 break; 145 146 case BRANCHES: 147 insn->type = NORMAL_INSN; 148 { 149 insn_template *current_optab = (insn_template *) tic30_optab; 150 151 for (; current_optab < tic30_optab_end; current_optab++) 152 { 153 if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word)) 154 { 155 if (current_optab->operand_types[0] & Imm24) 156 { 157 if ((current_optab->base_opcode & BR_IMM_IDEN) 158 == (insn_word & BR_IMM_IDEN)) 159 { 160 insn->tm = current_optab; 161 break; 162 } 163 } 164 else if (current_optab->operands > 0) 165 { 166 if ((current_optab->base_opcode & BR_COND_IDEN) 167 == (insn_word & BR_COND_IDEN)) 168 { 169 insn->tm = current_optab; 170 break; 171 } 172 } 173 else 174 { 175 if ((current_optab->base_opcode & (BR_COND_IDEN | 0x00800000)) 176 == (insn_word & (BR_COND_IDEN | 0x00800000))) 177 { 178 insn->tm = current_optab; 179 break; 180 } 181 } 182 } 183 } 184 } 185 break; 186 default: 187 return 0; 188 } 189 return 1; 190 } 191 192 static int 193 get_register_operand (unsigned char fragment, char *buffer) 194 { 195 const reg *current_reg = tic30_regtab; 196 197 if (buffer == NULL) 198 return 0; 199 for (; current_reg < tic30_regtab_end; current_reg++) 200 { 201 if ((fragment & 0x1F) == current_reg->opcode) 202 { 203 strcpy (buffer, current_reg->name); 204 return 1; 205 } 206 } 207 return 0; 208 } 209 210 static int 211 get_indirect_operand (unsigned short fragment, 212 int size, 213 char *buffer) 214 { 215 unsigned char mod; 216 unsigned arnum; 217 unsigned char disp; 218 219 if (buffer == NULL) 220 return 0; 221 /* Determine which bits identify the sections of the indirect 222 operand based on the size in bytes. */ 223 switch (size) 224 { 225 case 1: 226 mod = (fragment & 0x00F8) >> 3; 227 arnum = (fragment & 0x0007); 228 disp = 0; 229 break; 230 case 2: 231 mod = (fragment & 0xF800) >> 11; 232 arnum = (fragment & 0x0700) >> 8; 233 disp = (fragment & 0x00FF); 234 break; 235 default: 236 return 0; 237 } 238 { 239 const ind_addr_type *current_ind = tic30_indaddr_tab; 240 241 for (; current_ind < tic30_indaddrtab_end; current_ind++) 242 { 243 if (current_ind->modfield == mod) 244 { 245 if (current_ind->displacement == IMPLIED_DISP && size == 2) 246 continue; 247 248 else 249 { 250 size_t i, len; 251 int bufcnt; 252 253 len = strlen (current_ind->syntax); 254 for (i = 0, bufcnt = 0; i < len; i++, bufcnt++) 255 { 256 buffer[bufcnt] = current_ind->syntax[i]; 257 if (buffer[bufcnt - 1] == 'a' && buffer[bufcnt] == 'r') 258 buffer[++bufcnt] = arnum + '0'; 259 if (buffer[bufcnt] == '(' 260 && current_ind->displacement == DISP_REQUIRED) 261 { 262 sprintf (&buffer[bufcnt + 1], "%u", disp); 263 bufcnt += strlen (&buffer[bufcnt + 1]); 264 } 265 } 266 buffer[bufcnt + 1] = '\0'; 267 break; 268 } 269 } 270 } 271 } 272 return 1; 273 } 274 275 static int 276 cnvt_tmsfloat_ieee (unsigned long tmsfloat, int size, float *ieeefloat) 277 { 278 unsigned long exponent, sign, mant; 279 union 280 { 281 unsigned long l; 282 float f; 283 } val; 284 285 if (size == 2) 286 { 287 if ((tmsfloat & 0x0000F000) == 0x00008000) 288 tmsfloat = 0x80000000; 289 else 290 { 291 tmsfloat <<= 16; 292 tmsfloat = (long) tmsfloat >> 4; 293 } 294 } 295 exponent = tmsfloat & 0xFF000000; 296 if (exponent == 0x80000000) 297 { 298 *ieeefloat = 0.0; 299 return 1; 300 } 301 exponent += 0x7F000000; 302 sign = (tmsfloat & 0x00800000) << 8; 303 mant = tmsfloat & 0x007FFFFF; 304 if (exponent == 0xFF000000) 305 { 306 if (mant == 0) 307 *ieeefloat = ERANGE; 308 #ifdef HUGE_VALF 309 if (sign == 0) 310 *ieeefloat = HUGE_VALF; 311 else 312 *ieeefloat = -HUGE_VALF; 313 #else 314 if (sign == 0) 315 *ieeefloat = 1.0 / 0.0; 316 else 317 *ieeefloat = -1.0 / 0.0; 318 #endif 319 return 1; 320 } 321 exponent >>= 1; 322 if (sign) 323 { 324 mant = (~mant) & 0x007FFFFF; 325 mant += 1; 326 exponent += mant & 0x00800000; 327 exponent &= 0x7F800000; 328 mant &= 0x007FFFFF; 329 } 330 if (tmsfloat == 0x80000000) 331 sign = mant = exponent = 0; 332 tmsfloat = sign | exponent | mant; 333 val.l = tmsfloat; 334 *ieeefloat = val.f; 335 return 1; 336 } 337 338 static int 339 print_two_operand (disassemble_info *info, 340 unsigned long insn_word, 341 struct instruction *insn) 342 { 343 char name[12]; 344 char operand[2][13] = 345 { 346 {0}, 347 {0} 348 }; 349 float f_number; 350 351 if (insn->tm == NULL) 352 return 0; 353 strcpy (name, insn->tm->name); 354 if (insn->tm->opcode_modifier == AddressMode) 355 { 356 int src_op, dest_op; 357 /* Determine whether instruction is a store or a normal instruction. */ 358 if ((insn->tm->operand_types[1] & (Direct | Indirect)) 359 == (Direct | Indirect)) 360 { 361 src_op = 1; 362 dest_op = 0; 363 } 364 else 365 { 366 src_op = 0; 367 dest_op = 1; 368 } 369 /* Get the destination register. */ 370 if (insn->tm->operands == 2) 371 get_register_operand ((insn_word & 0x001F0000) >> 16, operand[dest_op]); 372 /* Get the source operand based on addressing mode. */ 373 switch (insn_word & AddressMode) 374 { 375 case AM_REGISTER: 376 /* Check for the NOP instruction before getting the operand. */ 377 if ((insn->tm->operand_types[0] & NotReq) == 0) 378 get_register_operand ((insn_word & 0x0000001F), operand[src_op]); 379 break; 380 case AM_DIRECT: 381 sprintf (operand[src_op], "@0x%lX", (insn_word & 0x0000FFFF)); 382 break; 383 case AM_INDIRECT: 384 get_indirect_operand ((insn_word & 0x0000FFFF), 2, operand[src_op]); 385 break; 386 case AM_IMM: 387 /* Get the value of the immediate operand based on variable type. */ 388 switch (insn->tm->imm_arg_type) 389 { 390 case Imm_Float: 391 cnvt_tmsfloat_ieee ((insn_word & 0x0000FFFF), 2, &f_number); 392 sprintf (operand[src_op], "%2.2f", f_number); 393 break; 394 case Imm_SInt: 395 sprintf (operand[src_op], "%d", (short) (insn_word & 0x0000FFFF)); 396 break; 397 case Imm_UInt: 398 sprintf (operand[src_op], "%lu", (insn_word & 0x0000FFFF)); 399 break; 400 default: 401 return 0; 402 } 403 /* Handle special case for LDP instruction. */ 404 if ((insn_word & 0xFFFFFF00) == LDP_INSN) 405 { 406 strcpy (name, "ldp"); 407 sprintf (operand[0], "0x%06lX", (insn_word & 0x000000FF) << 16); 408 operand[1][0] = '\0'; 409 } 410 } 411 } 412 /* Handle case for stack and rotate instructions. */ 413 else if (insn->tm->operands == 1) 414 { 415 if (insn->tm->opcode_modifier == StackOp) 416 get_register_operand ((insn_word & 0x001F0000) >> 16, operand[0]); 417 } 418 /* Output instruction to stream. */ 419 info->fprintf_func (info->stream, " %s %s%c%s", name, 420 operand[0][0] ? operand[0] : "", 421 operand[1][0] ? ',' : ' ', 422 operand[1][0] ? operand[1] : ""); 423 return 1; 424 } 425 426 static int 427 print_three_operand (disassemble_info *info, 428 unsigned long insn_word, 429 struct instruction *insn) 430 { 431 char operand[3][13] = 432 { 433 {0}, 434 {0}, 435 {0} 436 }; 437 438 if (insn->tm == NULL) 439 return 0; 440 switch (insn_word & AddressMode) 441 { 442 case AM_REGISTER: 443 get_register_operand ((insn_word & 0x000000FF), operand[0]); 444 get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]); 445 break; 446 case AM_DIRECT: 447 get_register_operand ((insn_word & 0x000000FF), operand[0]); 448 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]); 449 break; 450 case AM_INDIRECT: 451 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]); 452 get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]); 453 break; 454 case AM_IMM: 455 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]); 456 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]); 457 break; 458 default: 459 return 0; 460 } 461 if (insn->tm->operands == 3) 462 get_register_operand ((insn_word & 0x001F0000) >> 16, operand[2]); 463 info->fprintf_func (info->stream, " %s %s,%s%c%s", insn->tm->name, 464 operand[0], operand[1], 465 operand[2][0] ? ',' : ' ', 466 operand[2][0] ? operand[2] : ""); 467 return 1; 468 } 469 470 static int 471 print_par_insn (disassemble_info *info, 472 unsigned long insn_word, 473 struct instruction *insn) 474 { 475 size_t i, len; 476 char *name1, *name2; 477 char operand[2][3][13] = 478 { 479 { 480 {0}, 481 {0}, 482 {0} 483 }, 484 { 485 {0}, 486 {0}, 487 {0} 488 } 489 }; 490 491 if (insn->ptm == NULL) 492 return 0; 493 /* Parse out the names of each of the parallel instructions from the 494 q_insn1_insn2 format. */ 495 name1 = (char *) strdup (insn->ptm->name + 2); 496 name2 = ""; 497 len = strlen (name1); 498 for (i = 0; i < len; i++) 499 { 500 if (name1[i] == '_') 501 { 502 name2 = &name1[i + 1]; 503 name1[i] = '\0'; 504 break; 505 } 506 } 507 /* Get the operands of the instruction based on the operand order. */ 508 switch (insn->ptm->oporder) 509 { 510 case OO_4op1: 511 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]); 512 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]); 513 get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]); 514 get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]); 515 break; 516 case OO_4op2: 517 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]); 518 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]); 519 get_register_operand ((insn_word >> 19) & 0x07, operand[1][1]); 520 get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]); 521 break; 522 case OO_4op3: 523 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]); 524 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]); 525 get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]); 526 get_register_operand ((insn_word >> 22) & 0x07, operand[0][0]); 527 break; 528 case OO_5op1: 529 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]); 530 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]); 531 get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]); 532 get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]); 533 get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]); 534 break; 535 case OO_5op2: 536 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]); 537 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]); 538 get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]); 539 get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]); 540 get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]); 541 break; 542 case OO_PField: 543 if (insn_word & 0x00800000) 544 get_register_operand (0x01, operand[0][2]); 545 else 546 get_register_operand (0x00, operand[0][2]); 547 if (insn_word & 0x00400000) 548 get_register_operand (0x03, operand[1][2]); 549 else 550 get_register_operand (0x02, operand[1][2]); 551 switch (insn_word & P_FIELD) 552 { 553 case 0x00000000: 554 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]); 555 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]); 556 get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]); 557 get_register_operand ((insn_word >> 19) & 0x07, operand[1][0]); 558 break; 559 case 0x01000000: 560 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][0]); 561 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]); 562 get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]); 563 get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]); 564 break; 565 case 0x02000000: 566 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]); 567 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]); 568 get_register_operand ((insn_word >> 16) & 0x07, operand[0][1]); 569 get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]); 570 break; 571 case 0x03000000: 572 get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]); 573 get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]); 574 get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]); 575 get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]); 576 break; 577 } 578 break; 579 default: 580 return 0; 581 } 582 info->fprintf_func (info->stream, " %s %s,%s%c%s", name1, 583 operand[0][0], operand[0][1], 584 operand[0][2][0] ? ',' : ' ', 585 operand[0][2][0] ? operand[0][2] : ""); 586 info->fprintf_func (info->stream, "\n\t\t\t|| %s %s,%s%c%s", name2, 587 operand[1][0], operand[1][1], 588 operand[1][2][0] ? ',' : ' ', 589 operand[1][2][0] ? operand[1][2] : ""); 590 free (name1); 591 return 1; 592 } 593 594 static int 595 print_branch (disassemble_info *info, 596 unsigned long insn_word, 597 struct instruction *insn) 598 { 599 char operand[2][13] = 600 { 601 {0}, 602 {0} 603 }; 604 unsigned long address; 605 int print_label = 0; 606 607 if (insn->tm == NULL) 608 return 0; 609 /* Get the operands for 24-bit immediate jumps. */ 610 if (insn->tm->operand_types[0] & Imm24) 611 { 612 address = insn_word & 0x00FFFFFF; 613 sprintf (operand[0], "0x%lX", address); 614 print_label = 1; 615 } 616 /* Get the operand for the trap instruction. */ 617 else if (insn->tm->operand_types[0] & IVector) 618 { 619 address = insn_word & 0x0000001F; 620 sprintf (operand[0], "0x%lX", address); 621 } 622 else 623 { 624 address = insn_word & 0x0000FFFF; 625 /* Get the operands for the DB instructions. */ 626 if (insn->tm->operands == 2) 627 { 628 get_register_operand (((insn_word & 0x01C00000) >> 22) + REG_AR0, operand[0]); 629 if (insn_word & PCRel) 630 { 631 sprintf (operand[1], "%d", (short) address); 632 print_label = 1; 633 } 634 else 635 get_register_operand (insn_word & 0x0000001F, operand[1]); 636 } 637 /* Get the operands for the standard branches. */ 638 else if (insn->tm->operands == 1) 639 { 640 if (insn_word & PCRel) 641 { 642 address = (short) address; 643 sprintf (operand[0], "%ld", address); 644 print_label = 1; 645 } 646 else 647 get_register_operand (insn_word & 0x0000001F, operand[0]); 648 } 649 } 650 info->fprintf_func (info->stream, " %s %s%c%s", insn->tm->name, 651 operand[0][0] ? operand[0] : "", 652 operand[1][0] ? ',' : ' ', 653 operand[1][0] ? operand[1] : ""); 654 /* Print destination of branch in relation to current symbol. */ 655 if (print_label && info->symbols) 656 { 657 asymbol *sym = *info->symbols; 658 659 if ((insn->tm->opcode_modifier == PCRel) && (insn_word & PCRel)) 660 { 661 address = (_pc + 1 + (short) address) - ((sym->section->vma + sym->value) / 4); 662 /* Check for delayed instruction, if so adjust destination. */ 663 if (insn_word & 0x00200000) 664 address += 2; 665 } 666 else 667 { 668 address -= ((sym->section->vma + sym->value) / 4); 669 } 670 if (address == 0) 671 info->fprintf_func (info->stream, " <%s>", sym->name); 672 else 673 info->fprintf_func (info->stream, " <%s %c %d>", sym->name, 674 ((short) address < 0) ? '-' : '+', 675 abs (address)); 676 } 677 return 1; 678 } 679 680 int 681 print_insn_tic30 (bfd_vma pc, disassemble_info *info) 682 { 683 unsigned long insn_word; 684 struct instruction insn = { 0, NULL, NULL }; 685 bfd_vma bufaddr = pc - info->buffer_vma; 686 687 /* Obtain the current instruction word from the buffer. */ 688 insn_word = (*(info->buffer + bufaddr) << 24) | (*(info->buffer + bufaddr + 1) << 16) | 689 (*(info->buffer + bufaddr + 2) << 8) | *(info->buffer + bufaddr + 3); 690 _pc = pc / 4; 691 /* Get the instruction refered to by the current instruction word 692 and print it out based on its type. */ 693 if (!get_tic30_instruction (insn_word, &insn)) 694 return -1; 695 switch (GET_TYPE (insn_word)) 696 { 697 case TWO_OPERAND_1: 698 case TWO_OPERAND_2: 699 if (!print_two_operand (info, insn_word, &insn)) 700 return -1; 701 break; 702 case THREE_OPERAND: 703 if (!print_three_operand (info, insn_word, &insn)) 704 return -1; 705 break; 706 case PAR_STORE: 707 case MUL_ADDS: 708 if (!print_par_insn (info, insn_word, &insn)) 709 return -1; 710 break; 711 case BRANCHES: 712 if (!print_branch (info, insn_word, &insn)) 713 return -1; 714 break; 715 } 716 return 4; 717 } 718