1208842Snwhitehorn/* Instruction printing code for the ARC. 2208842Snwhitehorn Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005 3208842Snwhitehorn Free Software Foundation, Inc. 4208842Snwhitehorn Contributed by Doug Evans (dje@cygnus.com). 5208842Snwhitehorn 6208842Snwhitehorn This program is free software; you can redistribute it and/or modify 7208842Snwhitehorn it under the terms of the GNU General Public License as published by 8208842Snwhitehorn the Free Software Foundation; either version 2 of the License, or 9208842Snwhitehorn (at your option) any later version. 10208842Snwhitehorn 11208842Snwhitehorn This program is distributed in the hope that it will be useful, 12208842Snwhitehorn but WITHOUT ANY WARRANTY; without even the implied warranty of 13208842Snwhitehorn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14208842Snwhitehorn GNU General Public License for more details. 15208842Snwhitehorn 16208842Snwhitehorn You should have received a copy of the GNU General Public License 17208842Snwhitehorn along with this program; if not, write to the Free Software 18208842Snwhitehorn Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19208842Snwhitehorn MA 02110-1301, USA. */ 20208842Snwhitehorn 21208842Snwhitehorn#include "ansidecl.h" 22208842Snwhitehorn#include "libiberty.h" 23208842Snwhitehorn#include "dis-asm.h" 24208842Snwhitehorn#include "opcode/arc.h" 25208842Snwhitehorn#include "elf-bfd.h" 26208842Snwhitehorn#include "elf/arc.h" 27208842Snwhitehorn#include <string.h> 28208842Snwhitehorn#include "opintl.h" 29208842Snwhitehorn 30208842Snwhitehorn#include <stdarg.h> 31208842Snwhitehorn#include "arc-dis.h" 32208842Snwhitehorn#include "arc-ext.h" 33208842Snwhitehorn 34208842Snwhitehorn#ifndef dbg 35208842Snwhitehorn#define dbg (0) 36208842Snwhitehorn#endif 37208842Snwhitehorn 38208842Snwhitehorn/* Classification of the opcodes for the decoder to print 39208842Snwhitehorn the instructions. */ 40208842Snwhitehorn 41208842Snwhitehorntypedef enum 42208842Snwhitehorn{ 43208842Snwhitehorn CLASS_A4_ARITH, 44208842Snwhitehorn CLASS_A4_OP3_GENERAL, 45208842Snwhitehorn CLASS_A4_FLAG, 46208842Snwhitehorn /* All branches other than JC. */ 47208842Snwhitehorn CLASS_A4_BRANCH, 48208842Snwhitehorn CLASS_A4_JC , 49208842Snwhitehorn /* All loads other than immediate 50208842Snwhitehorn indexed loads. */ 51208842Snwhitehorn CLASS_A4_LD0, 52208842Snwhitehorn CLASS_A4_LD1, 53208842Snwhitehorn CLASS_A4_ST, 54208842Snwhitehorn CLASS_A4_SR, 55208842Snwhitehorn /* All single operand instructions. */ 56208842Snwhitehorn CLASS_A4_OP3_SUBOPC3F, 57208842Snwhitehorn CLASS_A4_LR 58208842Snwhitehorn} a4_decoding_class; 59208842Snwhitehorn 60208842Snwhitehorn#define BIT(word,n) ((word) & (1 << n)) 61208842Snwhitehorn#define BITS(word,s,e) (((word) << (31 - e)) >> (s + (31 - e))) 62208842Snwhitehorn#define OPCODE(word) (BITS ((word), 27, 31)) 63208842Snwhitehorn#define FIELDA(word) (BITS ((word), 21, 26)) 64208842Snwhitehorn#define FIELDB(word) (BITS ((word), 15, 20)) 65208842Snwhitehorn#define FIELDC(word) (BITS ((word), 9, 14)) 66208842Snwhitehorn 67208842Snwhitehorn/* FIELD D is signed in all of its uses, so we make sure argument is 68208842Snwhitehorn treated as signed for bit shifting purposes: */ 69208842Snwhitehorn#define FIELDD(word) (BITS (((signed int)word), 0, 8)) 70208842Snwhitehorn 71208842Snwhitehorn#define PUT_NEXT_WORD_IN(a) \ 72208842Snwhitehorn do \ 73208842Snwhitehorn { \ 74208842Snwhitehorn if (is_limm == 1 && !NEXT_WORD (1)) \ 75208842Snwhitehorn mwerror (state, _("Illegal limm reference in last instruction!\n")); \ 76208842Snwhitehorn a = state->words[1]; \ 77208842Snwhitehorn } \ 78208842Snwhitehorn while (0) 79208842Snwhitehorn 80208842Snwhitehorn#define CHECK_FLAG_COND_NULLIFY() \ 81208842Snwhitehorn do \ 82208842Snwhitehorn { \ 83208842Snwhitehorn if (is_shimm == 0) \ 84208842Snwhitehorn { \ 85208842Snwhitehorn flag = BIT (state->words[0], 8); \ 86208842Snwhitehorn state->nullifyMode = BITS (state->words[0], 5, 6); \ 87208842Snwhitehorn cond = BITS (state->words[0], 0, 4); \ 88208842Snwhitehorn } \ 89208842Snwhitehorn } \ 90208842Snwhitehorn while (0) 91208842Snwhitehorn 92208842Snwhitehorn#define CHECK_COND() \ 93208842Snwhitehorn do \ 94208842Snwhitehorn { \ 95208842Snwhitehorn if (is_shimm == 0) \ 96208842Snwhitehorn cond = BITS (state->words[0], 0, 4); \ 97208842Snwhitehorn } \ 98208842Snwhitehorn while (0) 99208842Snwhitehorn 100208842Snwhitehorn#define CHECK_FIELD(field) \ 101208842Snwhitehorn do \ 102208842Snwhitehorn { \ 103208842Snwhitehorn if (field == 62) \ 104208842Snwhitehorn { \ 105208842Snwhitehorn is_limm++; \ 106208842Snwhitehorn field##isReg = 0; \ 107208842Snwhitehorn PUT_NEXT_WORD_IN (field); \ 108208842Snwhitehorn limm_value = field; \ 109208842Snwhitehorn } \ 110208842Snwhitehorn else if (field > 60) \ 111208842Snwhitehorn { \ 112208842Snwhitehorn field##isReg = 0; \ 113208842Snwhitehorn is_shimm++; \ 114208842Snwhitehorn flag = (field == 61); \ 115208842Snwhitehorn field = FIELDD (state->words[0]); \ 116208842Snwhitehorn } \ 117208842Snwhitehorn } \ 118208842Snwhitehorn while (0) 119208842Snwhitehorn 120208842Snwhitehorn#define CHECK_FIELD_A() \ 121208842Snwhitehorn do \ 122208842Snwhitehorn { \ 123208842Snwhitehorn fieldA = FIELDA (state->words[0]); \ 124208842Snwhitehorn if (fieldA > 60) \ 125208842Snwhitehorn { \ 126208842Snwhitehorn fieldAisReg = 0; \ 127208842Snwhitehorn fieldA = 0; \ 128208842Snwhitehorn } \ 129208842Snwhitehorn } \ 130208842Snwhitehorn while (0) 131208842Snwhitehorn 132208842Snwhitehorn#define CHECK_FIELD_B() \ 133208842Snwhitehorn do \ 134208842Snwhitehorn { \ 135208842Snwhitehorn fieldB = FIELDB (state->words[0]); \ 136208842Snwhitehorn CHECK_FIELD (fieldB); \ 137208842Snwhitehorn } \ 138208842Snwhitehorn while (0) 139208842Snwhitehorn 140208842Snwhitehorn#define CHECK_FIELD_C() \ 141208842Snwhitehorn do \ 142208842Snwhitehorn { \ 143208842Snwhitehorn fieldC = FIELDC (state->words[0]); \ 144208842Snwhitehorn CHECK_FIELD (fieldC); \ 145208842Snwhitehorn } \ 146208842Snwhitehorn while (0) 147208842Snwhitehorn 148208842Snwhitehorn#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257)) 149208842Snwhitehorn#define IS_REG(x) (field##x##isReg) 150208842Snwhitehorn#define WRITE_FORMAT_LB_Rx_RB(x) WRITE_FORMAT (x, "[","]","","") 151208842Snwhitehorn#define WRITE_FORMAT_x_COMMA_LB(x) WRITE_FORMAT (x, "",",[","",",[") 152208842Snwhitehorn#define WRITE_FORMAT_COMMA_x_RB(x) WRITE_FORMAT (x, ",","]",",","]") 153208842Snwhitehorn#define WRITE_FORMAT_x_RB(x) WRITE_FORMAT (x, "","]","","]") 154208842Snwhitehorn#define WRITE_FORMAT_COMMA_x(x) WRITE_FORMAT (x, ",","",",","") 155208842Snwhitehorn#define WRITE_FORMAT_x_COMMA(x) WRITE_FORMAT (x, "",",","",",") 156208842Snwhitehorn#define WRITE_FORMAT_x(x) WRITE_FORMAT (x, "","","","") 157208842Snwhitehorn#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString, \ 158208842Snwhitehorn (IS_REG (x) ? cb1"%r"ca1 : \ 159208842Snwhitehorn usesAuxReg ? cb"%a"ca : \ 160208842Snwhitehorn IS_SMALL (x) ? cb"%d"ca : cb"%h"ca)) 161208842Snwhitehorn#define WRITE_FORMAT_RB() strcat (formatString, "]") 162208842Snwhitehorn#define WRITE_COMMENT(str) (state->comm[state->commNum++] = (str)) 163208842Snwhitehorn#define WRITE_NOP_COMMENT() if (!fieldAisReg && !flag) WRITE_COMMENT ("nop"); 164208842Snwhitehorn 165208842Snwhitehorn#define NEXT_WORD(x) (offset += 4, state->words[x]) 166208842Snwhitehorn 167208842Snwhitehorn#define add_target(x) (state->targets[state->tcnt++] = (x)) 168208842Snwhitehorn 169208842Snwhitehornstatic char comment_prefix[] = "\t; "; 170208842Snwhitehorn 171208842Snwhitehornstatic const char * 172208842Snwhitehorncore_reg_name (struct arcDisState * state, int val) 173208842Snwhitehorn{ 174208842Snwhitehorn if (state->coreRegName) 175208842Snwhitehorn return (*state->coreRegName)(state->_this, val); 176208842Snwhitehorn return 0; 177208842Snwhitehorn} 178208842Snwhitehorn 179208842Snwhitehornstatic const char * 180208842Snwhitehornaux_reg_name (struct arcDisState * state, int val) 181208842Snwhitehorn{ 182208842Snwhitehorn if (state->auxRegName) 183208842Snwhitehorn return (*state->auxRegName)(state->_this, val); 184208842Snwhitehorn return 0; 185208842Snwhitehorn} 186208842Snwhitehorn 187208842Snwhitehornstatic const char * 188208842Snwhitehorncond_code_name (struct arcDisState * state, int val) 189208842Snwhitehorn{ 190208842Snwhitehorn if (state->condCodeName) 191208842Snwhitehorn return (*state->condCodeName)(state->_this, val); 192208842Snwhitehorn return 0; 193208842Snwhitehorn} 194208842Snwhitehorn 195208842Snwhitehornstatic const char * 196208842Snwhitehorninstruction_name (struct arcDisState * state, 197208842Snwhitehorn int op1, 198208842Snwhitehorn int op2, 199208842Snwhitehorn int * flags) 200208842Snwhitehorn{ 201208842Snwhitehorn if (state->instName) 202208842Snwhitehorn return (*state->instName)(state->_this, op1, op2, flags); 203208842Snwhitehorn return 0; 204208842Snwhitehorn} 205208842Snwhitehorn 206208842Snwhitehornstatic void 207208842Snwhitehornmwerror (struct arcDisState * state, const char * msg) 208208842Snwhitehorn{ 209208842Snwhitehorn if (state->err != 0) 210208842Snwhitehorn (*state->err)(state->_this, (msg)); 211208842Snwhitehorn} 212208842Snwhitehorn 213208842Snwhitehornstatic const char * 214208842Snwhitehornpost_address (struct arcDisState * state, int addr) 215208842Snwhitehorn{ 216208842Snwhitehorn static char id[3 * ARRAY_SIZE (state->addresses)]; 217208842Snwhitehorn int j, i = state->acnt; 218208842Snwhitehorn 219208842Snwhitehorn if (i < ((int) ARRAY_SIZE (state->addresses))) 220208842Snwhitehorn { 221208842Snwhitehorn state->addresses[i] = addr; 222208842Snwhitehorn ++state->acnt; 223208842Snwhitehorn j = i*3; 224208842Snwhitehorn id[j+0] = '@'; 225208842Snwhitehorn id[j+1] = '0'+i; 226208842Snwhitehorn id[j+2] = 0; 227208842Snwhitehorn 228208842Snwhitehorn return id + j; 229208842Snwhitehorn } 230208842Snwhitehorn return ""; 231208842Snwhitehorn} 232208842Snwhitehorn 233208842Snwhitehornstatic void 234208842Snwhitehornarc_sprintf (struct arcDisState *state, char *buf, const char *format, ...) 235208842Snwhitehorn{ 236208842Snwhitehorn char *bp; 237208842Snwhitehorn const char *p; 238208842Snwhitehorn int size, leading_zero, regMap[2]; 239208842Snwhitehorn long auxNum; 240208842Snwhitehorn va_list ap; 241208842Snwhitehorn 242208842Snwhitehorn va_start (ap, format); 243208842Snwhitehorn 244208842Snwhitehorn bp = buf; 245208842Snwhitehorn *bp = 0; 246208842Snwhitehorn p = format; 247208842Snwhitehorn auxNum = -1; 248208842Snwhitehorn regMap[0] = 0; 249208842Snwhitehorn regMap[1] = 0; 250208842Snwhitehorn 251208842Snwhitehorn while (1) 252208842Snwhitehorn switch (*p++) 253208842Snwhitehorn { 254208842Snwhitehorn case 0: 255208842Snwhitehorn goto DOCOMM; /* (return) */ 256208842Snwhitehorn default: 257208842Snwhitehorn *bp++ = p[-1]; 258208842Snwhitehorn break; 259208842Snwhitehorn case '%': 260208842Snwhitehorn size = 0; 261208842Snwhitehorn leading_zero = 0; 262208842Snwhitehorn RETRY: ; 263 switch (*p++) 264 { 265 case '0': 266 case '1': 267 case '2': 268 case '3': 269 case '4': 270 case '5': 271 case '6': 272 case '7': 273 case '8': 274 case '9': 275 { 276 /* size. */ 277 size = p[-1] - '0'; 278 if (size == 0) 279 leading_zero = 1; /* e.g. %08x */ 280 while (*p >= '0' && *p <= '9') 281 { 282 size = size * 10 + *p - '0'; 283 p++; 284 } 285 goto RETRY; 286 } 287#define inc_bp() bp = bp + strlen (bp) 288 289 case 'h': 290 { 291 unsigned u = va_arg (ap, int); 292 293 /* Hex. We can change the format to 0x%08x in 294 one place, here, if we wish. 295 We add underscores for easy reading. */ 296 if (u > 65536) 297 sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff); 298 else 299 sprintf (bp, "0x%x", u); 300 inc_bp (); 301 } 302 break; 303 case 'X': case 'x': 304 { 305 int val = va_arg (ap, int); 306 307 if (size != 0) 308 if (leading_zero) 309 sprintf (bp, "%0*x", size, val); 310 else 311 sprintf (bp, "%*x", size, val); 312 else 313 sprintf (bp, "%x", val); 314 inc_bp (); 315 } 316 break; 317 case 'd': 318 { 319 int val = va_arg (ap, int); 320 321 if (size != 0) 322 sprintf (bp, "%*d", size, val); 323 else 324 sprintf (bp, "%d", val); 325 inc_bp (); 326 } 327 break; 328 case 'r': 329 { 330 /* Register. */ 331 int val = va_arg (ap, int); 332 333#define REG2NAME(num, name) case num: sprintf (bp, ""name); \ 334 regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break; 335 336 switch (val) 337 { 338 REG2NAME (26, "gp"); 339 REG2NAME (27, "fp"); 340 REG2NAME (28, "sp"); 341 REG2NAME (29, "ilink1"); 342 REG2NAME (30, "ilink2"); 343 REG2NAME (31, "blink"); 344 REG2NAME (60, "lp_count"); 345 default: 346 { 347 const char * ext; 348 349 ext = core_reg_name (state, val); 350 if (ext) 351 sprintf (bp, "%s", ext); 352 else 353 sprintf (bp,"r%d",val); 354 } 355 break; 356 } 357 inc_bp (); 358 } break; 359 360 case 'a': 361 { 362 /* Aux Register. */ 363 int val = va_arg (ap, int); 364 365#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break; 366 367 switch (val) 368 { 369 AUXREG2NAME (0x0, "status"); 370 AUXREG2NAME (0x1, "semaphore"); 371 AUXREG2NAME (0x2, "lp_start"); 372 AUXREG2NAME (0x3, "lp_end"); 373 AUXREG2NAME (0x4, "identity"); 374 AUXREG2NAME (0x5, "debug"); 375 default: 376 { 377 const char *ext; 378 379 ext = aux_reg_name (state, val); 380 if (ext) 381 sprintf (bp, "%s", ext); 382 else 383 arc_sprintf (state, bp, "%h", val); 384 } 385 break; 386 } 387 inc_bp (); 388 } 389 break; 390 391 case 's': 392 { 393 sprintf (bp, "%s", va_arg (ap, char *)); 394 inc_bp (); 395 } 396 break; 397 398 default: 399 fprintf (stderr, "?? format %c\n", p[-1]); 400 break; 401 } 402 } 403 404 DOCOMM: *bp = 0; 405 va_end (ap); 406} 407 408static void 409write_comments_(struct arcDisState * state, 410 int shimm, 411 int is_limm, 412 long limm_value) 413{ 414 if (state->commentBuffer != 0) 415 { 416 int i; 417 418 if (is_limm) 419 { 420 const char *name = post_address (state, limm_value + shimm); 421 422 if (*name != 0) 423 WRITE_COMMENT (name); 424 } 425 for (i = 0; i < state->commNum; i++) 426 { 427 if (i == 0) 428 strcpy (state->commentBuffer, comment_prefix); 429 else 430 strcat (state->commentBuffer, ", "); 431 strncat (state->commentBuffer, state->comm[i], 432 sizeof (state->commentBuffer)); 433 } 434 } 435} 436 437#define write_comments2(x) write_comments_ (state, x, is_limm, limm_value) 438#define write_comments() write_comments2 (0) 439 440static const char *condName[] = 441{ 442 /* 0..15. */ 443 "" , "z" , "nz" , "p" , "n" , "c" , "nc" , "v" , 444 "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz" 445}; 446 447static void 448write_instr_name_(struct arcDisState * state, 449 const char * instrName, 450 int cond, 451 int condCodeIsPartOfName, 452 int flag, 453 int signExtend, 454 int addrWriteBack, 455 int directMem) 456{ 457 strcpy (state->instrBuffer, instrName); 458 459 if (cond > 0) 460 { 461 const char *cc = 0; 462 463 if (!condCodeIsPartOfName) 464 strcat (state->instrBuffer, "."); 465 466 if (cond < 16) 467 cc = condName[cond]; 468 else 469 cc = cond_code_name (state, cond); 470 471 if (!cc) 472 cc = "???"; 473 474 strcat (state->instrBuffer, cc); 475 } 476 477 if (flag) 478 strcat (state->instrBuffer, ".f"); 479 480 switch (state->nullifyMode) 481 { 482 case BR_exec_always: 483 strcat (state->instrBuffer, ".d"); 484 break; 485 case BR_exec_when_jump: 486 strcat (state->instrBuffer, ".jd"); 487 break; 488 } 489 490 if (signExtend) 491 strcat (state->instrBuffer, ".x"); 492 493 if (addrWriteBack) 494 strcat (state->instrBuffer, ".a"); 495 496 if (directMem) 497 strcat (state->instrBuffer, ".di"); 498} 499 500#define write_instr_name() \ 501 do \ 502 { \ 503 write_instr_name_(state, instrName,cond, condCodeIsPartOfName, \ 504 flag, signExtend, addrWriteBack, directMem); \ 505 formatString[0] = '\0'; \ 506 } \ 507 while (0) 508 509enum 510{ 511 op_LD0 = 0, op_LD1 = 1, op_ST = 2, op_3 = 3, 512 op_BC = 4, op_BLC = 5, op_LPC = 6, op_JC = 7, 513 op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11, 514 op_AND = 12, op_OR = 13, op_BIC = 14, op_XOR = 15 515}; 516 517extern disassemble_info tm_print_insn_info; 518 519static int 520dsmOneArcInst (bfd_vma addr, struct arcDisState * state) 521{ 522 int condCodeIsPartOfName = 0; 523 a4_decoding_class decodingClass; 524 const char * instrName; 525 int repeatsOp = 0; 526 int fieldAisReg = 1; 527 int fieldBisReg = 1; 528 int fieldCisReg = 1; 529 int fieldA; 530 int fieldB; 531 int fieldC = 0; 532 int flag = 0; 533 int cond = 0; 534 int is_shimm = 0; 535 int is_limm = 0; 536 long limm_value = 0; 537 int signExtend = 0; 538 int addrWriteBack = 0; 539 int directMem = 0; 540 int is_linked = 0; 541 int offset = 0; 542 int usesAuxReg = 0; 543 int flags; 544 int ignoreFirstOpd; 545 char formatString[60]; 546 547 state->instructionLen = 4; 548 state->nullifyMode = BR_exec_when_no_jump; 549 state->opWidth = 12; 550 state->isBranch = 0; 551 552 state->_mem_load = 0; 553 state->_ea_present = 0; 554 state->_load_len = 0; 555 state->ea_reg1 = no_reg; 556 state->ea_reg2 = no_reg; 557 state->_offset = 0; 558 559 if (! NEXT_WORD (0)) 560 return 0; 561 562 state->_opcode = OPCODE (state->words[0]); 563 instrName = 0; 564 decodingClass = CLASS_A4_ARITH; /* default! */ 565 repeatsOp = 0; 566 condCodeIsPartOfName=0; 567 state->commNum = 0; 568 state->tcnt = 0; 569 state->acnt = 0; 570 state->flow = noflow; 571 ignoreFirstOpd = 0; 572 573 if (state->commentBuffer) 574 state->commentBuffer[0] = '\0'; 575 576 switch (state->_opcode) 577 { 578 case op_LD0: 579 switch (BITS (state->words[0],1,2)) 580 { 581 case 0: 582 instrName = "ld"; 583 state->_load_len = 4; 584 break; 585 case 1: 586 instrName = "ldb"; 587 state->_load_len = 1; 588 break; 589 case 2: 590 instrName = "ldw"; 591 state->_load_len = 2; 592 break; 593 default: 594 instrName = "??? (0[3])"; 595 state->flow = invalid_instr; 596 break; 597 } 598 decodingClass = CLASS_A4_LD0; 599 break; 600 601 case op_LD1: 602 if (BIT (state->words[0],13)) 603 { 604 instrName = "lr"; 605 decodingClass = CLASS_A4_LR; 606 } 607 else 608 { 609 switch (BITS (state->words[0], 10, 11)) 610 { 611 case 0: 612 instrName = "ld"; 613 state->_load_len = 4; 614 break; 615 case 1: 616 instrName = "ldb"; 617 state->_load_len = 1; 618 break; 619 case 2: 620 instrName = "ldw"; 621 state->_load_len = 2; 622 break; 623 default: 624 instrName = "??? (1[3])"; 625 state->flow = invalid_instr; 626 break; 627 } 628 decodingClass = CLASS_A4_LD1; 629 } 630 break; 631 632 case op_ST: 633 if (BIT (state->words[0], 25)) 634 { 635 instrName = "sr"; 636 decodingClass = CLASS_A4_SR; 637 } 638 else 639 { 640 switch (BITS (state->words[0], 22, 23)) 641 { 642 case 0: 643 instrName = "st"; 644 break; 645 case 1: 646 instrName = "stb"; 647 break; 648 case 2: 649 instrName = "stw"; 650 break; 651 default: 652 instrName = "??? (2[3])"; 653 state->flow = invalid_instr; 654 break; 655 } 656 decodingClass = CLASS_A4_ST; 657 } 658 break; 659 660 case op_3: 661 decodingClass = CLASS_A4_OP3_GENERAL; /* default for opcode 3... */ 662 switch (FIELDC (state->words[0])) 663 { 664 case 0: 665 instrName = "flag"; 666 decodingClass = CLASS_A4_FLAG; 667 break; 668 case 1: 669 instrName = "asr"; 670 break; 671 case 2: 672 instrName = "lsr"; 673 break; 674 case 3: 675 instrName = "ror"; 676 break; 677 case 4: 678 instrName = "rrc"; 679 break; 680 case 5: 681 instrName = "sexb"; 682 break; 683 case 6: 684 instrName = "sexw"; 685 break; 686 case 7: 687 instrName = "extb"; 688 break; 689 case 8: 690 instrName = "extw"; 691 break; 692 case 0x3f: 693 { 694 decodingClass = CLASS_A4_OP3_SUBOPC3F; 695 switch (FIELDD (state->words[0])) 696 { 697 case 0: 698 instrName = "brk"; 699 break; 700 case 1: 701 instrName = "sleep"; 702 break; 703 case 2: 704 instrName = "swi"; 705 break; 706 default: 707 instrName = "???"; 708 state->flow=invalid_instr; 709 break; 710 } 711 } 712 break; 713 714 /* ARC Extension Library Instructions 715 NOTE: We assume that extension codes are these instrs. */ 716 default: 717 instrName = instruction_name (state, 718 state->_opcode, 719 FIELDC (state->words[0]), 720 &flags); 721 if (!instrName) 722 { 723 instrName = "???"; 724 state->flow = invalid_instr; 725 } 726 if (flags & IGNORE_FIRST_OPD) 727 ignoreFirstOpd = 1; 728 break; 729 } 730 break; 731 732 case op_BC: 733 instrName = "b"; 734 case op_BLC: 735 if (!instrName) 736 instrName = "bl"; 737 case op_LPC: 738 if (!instrName) 739 instrName = "lp"; 740 case op_JC: 741 if (!instrName) 742 { 743 if (BITS (state->words[0],9,9)) 744 { 745 instrName = "jl"; 746 is_linked = 1; 747 } 748 else 749 { 750 instrName = "j"; 751 is_linked = 0; 752 } 753 } 754 condCodeIsPartOfName = 1; 755 decodingClass = ((state->_opcode == op_JC) ? CLASS_A4_JC : CLASS_A4_BRANCH ); 756 state->isBranch = 1; 757 break; 758 759 case op_ADD: 760 case op_ADC: 761 case op_AND: 762 repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0])); 763 764 switch (state->_opcode) 765 { 766 case op_ADD: 767 instrName = (repeatsOp ? "asl" : "add"); 768 break; 769 case op_ADC: 770 instrName = (repeatsOp ? "rlc" : "adc"); 771 break; 772 case op_AND: 773 instrName = (repeatsOp ? "mov" : "and"); 774 break; 775 } 776 break; 777 778 case op_SUB: instrName = "sub"; 779 break; 780 case op_SBC: instrName = "sbc"; 781 break; 782 case op_OR: instrName = "or"; 783 break; 784 case op_BIC: instrName = "bic"; 785 break; 786 787 case op_XOR: 788 if (state->words[0] == 0x7fffffff) 789 { 790 /* NOP encoded as xor -1, -1, -1. */ 791 instrName = "nop"; 792 decodingClass = CLASS_A4_OP3_SUBOPC3F; 793 } 794 else 795 instrName = "xor"; 796 break; 797 798 default: 799 instrName = instruction_name (state,state->_opcode,0,&flags); 800 /* if (instrName) printf("FLAGS=0x%x\n", flags); */ 801 if (!instrName) 802 { 803 instrName = "???"; 804 state->flow=invalid_instr; 805 } 806 if (flags & IGNORE_FIRST_OPD) 807 ignoreFirstOpd = 1; 808 break; 809 } 810 811 fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now. */ 812 flag = cond = is_shimm = is_limm = 0; 813 state->nullifyMode = BR_exec_when_no_jump; /* 0 */ 814 signExtend = addrWriteBack = directMem = 0; 815 usesAuxReg = 0; 816 817 switch (decodingClass) 818 { 819 case CLASS_A4_ARITH: 820 CHECK_FIELD_A (); 821 CHECK_FIELD_B (); 822 if (!repeatsOp) 823 CHECK_FIELD_C (); 824 CHECK_FLAG_COND_NULLIFY (); 825 826 write_instr_name (); 827 if (!ignoreFirstOpd) 828 { 829 WRITE_FORMAT_x (A); 830 WRITE_FORMAT_COMMA_x (B); 831 if (!repeatsOp) 832 WRITE_FORMAT_COMMA_x (C); 833 WRITE_NOP_COMMENT (); 834 arc_sprintf (state, state->operandBuffer, formatString, 835 fieldA, fieldB, fieldC); 836 } 837 else 838 { 839 WRITE_FORMAT_x (B); 840 if (!repeatsOp) 841 WRITE_FORMAT_COMMA_x (C); 842 arc_sprintf (state, state->operandBuffer, formatString, 843 fieldB, fieldC); 844 } 845 write_comments (); 846 break; 847 848 case CLASS_A4_OP3_GENERAL: 849 CHECK_FIELD_A (); 850 CHECK_FIELD_B (); 851 CHECK_FLAG_COND_NULLIFY (); 852 853 write_instr_name (); 854 if (!ignoreFirstOpd) 855 { 856 WRITE_FORMAT_x (A); 857 WRITE_FORMAT_COMMA_x (B); 858 WRITE_NOP_COMMENT (); 859 arc_sprintf (state, state->operandBuffer, formatString, 860 fieldA, fieldB); 861 } 862 else 863 { 864 WRITE_FORMAT_x (B); 865 arc_sprintf (state, state->operandBuffer, formatString, fieldB); 866 } 867 write_comments (); 868 break; 869 870 case CLASS_A4_FLAG: 871 CHECK_FIELD_B (); 872 CHECK_FLAG_COND_NULLIFY (); 873 flag = 0; /* This is the FLAG instruction -- it's redundant. */ 874 875 write_instr_name (); 876 WRITE_FORMAT_x (B); 877 arc_sprintf (state, state->operandBuffer, formatString, fieldB); 878 write_comments (); 879 break; 880 881 case CLASS_A4_BRANCH: 882 fieldA = BITS (state->words[0],7,26) << 2; 883 fieldA = (fieldA << 10) >> 10; /* Make it signed. */ 884 fieldA += addr + 4; 885 CHECK_FLAG_COND_NULLIFY (); 886 flag = 0; 887 888 write_instr_name (); 889 /* This address could be a label we know. Convert it. */ 890 if (state->_opcode != op_LPC /* LP */) 891 { 892 add_target (fieldA); /* For debugger. */ 893 state->flow = state->_opcode == op_BLC /* BL */ 894 ? direct_call 895 : direct_jump; 896 /* indirect calls are achieved by "lr blink,[status]; 897 lr dest<- func addr; j [dest]" */ 898 } 899 900 strcat (formatString, "%s"); /* Address/label name. */ 901 arc_sprintf (state, state->operandBuffer, formatString, 902 post_address (state, fieldA)); 903 write_comments (); 904 break; 905 906 case CLASS_A4_JC: 907 /* For op_JC -- jump to address specified. 908 Also covers jump and link--bit 9 of the instr. word 909 selects whether linked, thus "is_linked" is set above. */ 910 fieldA = 0; 911 CHECK_FIELD_B (); 912 CHECK_FLAG_COND_NULLIFY (); 913 914 if (!fieldBisReg) 915 { 916 fieldAisReg = 0; 917 fieldA = (fieldB >> 25) & 0x7F; /* Flags. */ 918 fieldB = (fieldB & 0xFFFFFF) << 2; 919 state->flow = is_linked ? direct_call : direct_jump; 920 add_target (fieldB); 921 /* Screwy JLcc requires .jd mode to execute correctly 922 but we pretend it is .nd (no delay slot). */ 923 if (is_linked && state->nullifyMode == BR_exec_when_jump) 924 state->nullifyMode = BR_exec_when_no_jump; 925 } 926 else 927 { 928 state->flow = is_linked ? indirect_call : indirect_jump; 929 /* We should also treat this as indirect call if NOT linked 930 but the preceding instruction was a "lr blink,[status]" 931 and we have a delay slot with "add blink,blink,2". 932 For now we can't detect such. */ 933 state->register_for_indirect_jump = fieldB; 934 } 935 936 write_instr_name (); 937 strcat (formatString, 938 IS_REG (B) ? "[%r]" : "%s"); /* Address/label name. */ 939 if (fieldA != 0) 940 { 941 fieldAisReg = 0; 942 WRITE_FORMAT_COMMA_x (A); 943 } 944 if (IS_REG (B)) 945 arc_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA); 946 else 947 arc_sprintf (state, state->operandBuffer, formatString, 948 post_address (state, fieldB), fieldA); 949 write_comments (); 950 break; 951 952 case CLASS_A4_LD0: 953 /* LD instruction. 954 B and C can be regs, or one (both?) can be limm. */ 955 CHECK_FIELD_A (); 956 CHECK_FIELD_B (); 957 CHECK_FIELD_C (); 958 if (dbg) 959 printf ("5:b reg %d %d c reg %d %d \n", 960 fieldBisReg,fieldB,fieldCisReg,fieldC); 961 state->_offset = 0; 962 state->_ea_present = 1; 963 if (fieldBisReg) 964 state->ea_reg1 = fieldB; 965 else 966 state->_offset += fieldB; 967 if (fieldCisReg) 968 state->ea_reg2 = fieldC; 969 else 970 state->_offset += fieldC; 971 state->_mem_load = 1; 972 973 directMem = BIT (state->words[0], 5); 974 addrWriteBack = BIT (state->words[0], 3); 975 signExtend = BIT (state->words[0], 0); 976 977 write_instr_name (); 978 WRITE_FORMAT_x_COMMA_LB(A); 979 if (fieldBisReg || fieldB != 0) 980 WRITE_FORMAT_x_COMMA (B); 981 else 982 fieldB = fieldC; 983 984 WRITE_FORMAT_x_RB (C); 985 arc_sprintf (state, state->operandBuffer, formatString, 986 fieldA, fieldB, fieldC); 987 write_comments (); 988 break; 989 990 case CLASS_A4_LD1: 991 /* LD instruction. */ 992 CHECK_FIELD_B (); 993 CHECK_FIELD_A (); 994 fieldC = FIELDD (state->words[0]); 995 996 if (dbg) 997 printf ("6:b reg %d %d c 0x%x \n", 998 fieldBisReg, fieldB, fieldC); 999 state->_ea_present = 1; 1000 state->_offset = fieldC; 1001 state->_mem_load = 1; 1002 if (fieldBisReg) 1003 state->ea_reg1 = fieldB; 1004 /* Field B is either a shimm (same as fieldC) or limm (different!) 1005 Say ea is not present, so only one of us will do the name lookup. */ 1006 else 1007 state->_offset += fieldB, state->_ea_present = 0; 1008 1009 directMem = BIT (state->words[0],14); 1010 addrWriteBack = BIT (state->words[0],12); 1011 signExtend = BIT (state->words[0],9); 1012 1013 write_instr_name (); 1014 WRITE_FORMAT_x_COMMA_LB (A); 1015 if (!fieldBisReg) 1016 { 1017 fieldB = state->_offset; 1018 WRITE_FORMAT_x_RB (B); 1019 } 1020 else 1021 { 1022 WRITE_FORMAT_x (B); 1023 if (fieldC != 0 && !BIT (state->words[0],13)) 1024 { 1025 fieldCisReg = 0; 1026 WRITE_FORMAT_COMMA_x_RB (C); 1027 } 1028 else 1029 WRITE_FORMAT_RB (); 1030 } 1031 arc_sprintf (state, state->operandBuffer, formatString, 1032 fieldA, fieldB, fieldC); 1033 write_comments (); 1034 break; 1035 1036 case CLASS_A4_ST: 1037 /* ST instruction. */ 1038 CHECK_FIELD_B(); 1039 CHECK_FIELD_C(); 1040 fieldA = FIELDD(state->words[0]); /* shimm */ 1041 1042 /* [B,A offset] */ 1043 if (dbg) printf("7:b reg %d %x off %x\n", 1044 fieldBisReg,fieldB,fieldA); 1045 state->_ea_present = 1; 1046 state->_offset = fieldA; 1047 if (fieldBisReg) 1048 state->ea_reg1 = fieldB; 1049 /* Field B is either a shimm (same as fieldA) or limm (different!) 1050 Say ea is not present, so only one of us will do the name lookup. 1051 (for is_limm we do the name translation here). */ 1052 else 1053 state->_offset += fieldB, state->_ea_present = 0; 1054 1055 directMem = BIT (state->words[0], 26); 1056 addrWriteBack = BIT (state->words[0], 24); 1057 1058 write_instr_name (); 1059 WRITE_FORMAT_x_COMMA_LB(C); 1060 1061 if (!fieldBisReg) 1062 { 1063 fieldB = state->_offset; 1064 WRITE_FORMAT_x_RB (B); 1065 } 1066 else 1067 { 1068 WRITE_FORMAT_x (B); 1069 if (fieldBisReg && fieldA != 0) 1070 { 1071 fieldAisReg = 0; 1072 WRITE_FORMAT_COMMA_x_RB(A); 1073 } 1074 else 1075 WRITE_FORMAT_RB(); 1076 } 1077 arc_sprintf (state, state->operandBuffer, formatString, 1078 fieldC, fieldB, fieldA); 1079 write_comments2 (fieldA); 1080 break; 1081 1082 case CLASS_A4_SR: 1083 /* SR instruction */ 1084 CHECK_FIELD_B(); 1085 CHECK_FIELD_C(); 1086 1087 write_instr_name (); 1088 WRITE_FORMAT_x_COMMA_LB(C); 1089 /* Try to print B as an aux reg if it is not a core reg. */ 1090 usesAuxReg = 1; 1091 WRITE_FORMAT_x (B); 1092 WRITE_FORMAT_RB (); 1093 arc_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB); 1094 write_comments (); 1095 break; 1096 1097 case CLASS_A4_OP3_SUBOPC3F: 1098 write_instr_name (); 1099 state->operandBuffer[0] = '\0'; 1100 break; 1101 1102 case CLASS_A4_LR: 1103 /* LR instruction */ 1104 CHECK_FIELD_A (); 1105 CHECK_FIELD_B (); 1106 1107 write_instr_name (); 1108 WRITE_FORMAT_x_COMMA_LB (A); 1109 /* Try to print B as an aux reg if it is not a core reg. */ 1110 usesAuxReg = 1; 1111 WRITE_FORMAT_x (B); 1112 WRITE_FORMAT_RB (); 1113 arc_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB); 1114 write_comments (); 1115 break; 1116 1117 default: 1118 mwerror (state, "Bad decoding class in ARC disassembler"); 1119 break; 1120 } 1121 1122 state->_cond = cond; 1123 return state->instructionLen = offset; 1124} 1125 1126 1127/* Returns the name the user specified core extension register. */ 1128 1129static const char * 1130_coreRegName(void * arg ATTRIBUTE_UNUSED, int regval) 1131{ 1132 return arcExtMap_coreRegName (regval); 1133} 1134 1135/* Returns the name the user specified AUX extension register. */ 1136 1137static const char * 1138_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval) 1139{ 1140 return arcExtMap_auxRegName(regval); 1141} 1142 1143/* Returns the name the user specified condition code name. */ 1144 1145static const char * 1146_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval) 1147{ 1148 return arcExtMap_condCodeName(regval); 1149} 1150 1151/* Returns the name the user specified extension instruction. */ 1152 1153static const char * 1154_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags) 1155{ 1156 return arcExtMap_instName(majop, minop, flags); 1157} 1158 1159/* Decode an instruction returning the size of the instruction 1160 in bytes or zero if unrecognized. */ 1161 1162static int 1163decodeInstr (bfd_vma address, /* Address of this instruction. */ 1164 disassemble_info * info) 1165{ 1166 int status; 1167 bfd_byte buffer[4]; 1168 struct arcDisState s; /* ARC Disassembler state. */ 1169 void *stream = info->stream; /* Output stream. */ 1170 fprintf_ftype func = info->fprintf_func; 1171 int bytes; 1172 1173 memset (&s, 0, sizeof(struct arcDisState)); 1174 1175 /* read first instruction */ 1176 status = (*info->read_memory_func) (address, buffer, 4, info); 1177 if (status != 0) 1178 { 1179 (*info->memory_error_func) (status, address, info); 1180 return 0; 1181 } 1182 if (info->endian == BFD_ENDIAN_LITTLE) 1183 s.words[0] = bfd_getl32(buffer); 1184 else 1185 s.words[0] = bfd_getb32(buffer); 1186 /* Always read second word in case of limm. */ 1187 1188 /* We ignore the result since last insn may not have a limm. */ 1189 status = (*info->read_memory_func) (address + 4, buffer, 4, info); 1190 if (info->endian == BFD_ENDIAN_LITTLE) 1191 s.words[1] = bfd_getl32(buffer); 1192 else 1193 s.words[1] = bfd_getb32(buffer); 1194 1195 s._this = &s; 1196 s.coreRegName = _coreRegName; 1197 s.auxRegName = _auxRegName; 1198 s.condCodeName = _condCodeName; 1199 s.instName = _instName; 1200 1201 /* Disassemble. */ 1202 bytes = dsmOneArcInst (address, (void *)& s); 1203 1204 /* Display the disassembly instruction. */ 1205 (*func) (stream, "%08lx ", s.words[0]); 1206 (*func) (stream, " "); 1207 (*func) (stream, "%-10s ", s.instrBuffer); 1208 1209 if (__TRANSLATION_REQUIRED (s)) 1210 { 1211 bfd_vma addr = s.addresses[s.operandBuffer[1] - '0']; 1212 1213 (*info->print_address_func) ((bfd_vma) addr, info); 1214 (*func) (stream, "\n"); 1215 } 1216 else 1217 (*func) (stream, "%s",s.operandBuffer); 1218 1219 return s.instructionLen; 1220} 1221 1222/* Return the print_insn function to use. 1223 Side effect: load (possibly empty) extension section */ 1224 1225disassembler_ftype 1226arc_get_disassembler (void *ptr) 1227{ 1228 if (ptr) 1229 build_ARC_extmap (ptr); 1230 return decodeInstr; 1231} 1232