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