138889Sjdp/* Instruction printing code for the ARC. 2218822Sdim Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005 385815Sobrien Free Software Foundation, Inc. 438889Sjdp Contributed by Doug Evans (dje@cygnus.com). 538889Sjdp 685815Sobrien This program is free software; you can redistribute it and/or modify 785815Sobrien it under the terms of the GNU General Public License as published by 885815Sobrien the Free Software Foundation; either version 2 of the License, or 985815Sobrien (at your option) any later version. 1038889Sjdp 1185815Sobrien This program is distributed in the hope that it will be useful, 1285815Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1385815Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1485815Sobrien GNU General Public License for more details. 1538889Sjdp 1685815Sobrien You should have received a copy of the GNU General Public License 1785815Sobrien along with this program; if not, write to the Free Software 18218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19218822Sdim MA 02110-1301, USA. */ 2038889Sjdp 21104834Sobrien#include "ansidecl.h" 22104834Sobrien#include "libiberty.h" 2338889Sjdp#include "dis-asm.h" 2438889Sjdp#include "opcode/arc.h" 2538889Sjdp#include "elf-bfd.h" 2638889Sjdp#include "elf/arc.h" 2785815Sobrien#include <string.h> 2860484Sobrien#include "opintl.h" 2938889Sjdp 3085815Sobrien#include <stdarg.h> 3185815Sobrien#include "arc-dis.h" 3285815Sobrien#include "arc-ext.h" 3338889Sjdp 3485815Sobrien#ifndef dbg 3585815Sobrien#define dbg (0) 3685815Sobrien#endif 3738889Sjdp 38218822Sdim/* Classification of the opcodes for the decoder to print 39218822Sdim the instructions. */ 40218822Sdim 41218822Sdimtypedef enum 42218822Sdim{ 43218822Sdim CLASS_A4_ARITH, 44218822Sdim CLASS_A4_OP3_GENERAL, 45218822Sdim CLASS_A4_FLAG, 46218822Sdim /* All branches other than JC. */ 47218822Sdim CLASS_A4_BRANCH, 48218822Sdim CLASS_A4_JC , 49218822Sdim /* All loads other than immediate 50218822Sdim indexed loads. */ 51218822Sdim CLASS_A4_LD0, 52218822Sdim CLASS_A4_LD1, 53218822Sdim CLASS_A4_ST, 54218822Sdim CLASS_A4_SR, 55218822Sdim /* All single operand instructions. */ 56218822Sdim CLASS_A4_OP3_SUBOPC3F, 57218822Sdim CLASS_A4_LR 58218822Sdim} a4_decoding_class; 59218822Sdim 6089857Sobrien#define BIT(word,n) ((word) & (1 << n)) 6189857Sobrien#define BITS(word,s,e) (((word) << (31 - e)) >> (s + (31 - e))) 6289857Sobrien#define OPCODE(word) (BITS ((word), 27, 31)) 6389857Sobrien#define FIELDA(word) (BITS ((word), 21, 26)) 6489857Sobrien#define FIELDB(word) (BITS ((word), 15, 20)) 6589857Sobrien#define FIELDC(word) (BITS ((word), 9, 14)) 6638889Sjdp 6785815Sobrien/* FIELD D is signed in all of its uses, so we make sure argument is 6885815Sobrien treated as signed for bit shifting purposes: */ 6989857Sobrien#define FIELDD(word) (BITS (((signed int)word), 0, 8)) 7085815Sobrien 7189857Sobrien#define PUT_NEXT_WORD_IN(a) \ 7289857Sobrien do \ 7389857Sobrien { \ 7489857Sobrien if (is_limm == 1 && !NEXT_WORD (1)) \ 7589857Sobrien mwerror (state, _("Illegal limm reference in last instruction!\n")); \ 7689857Sobrien a = state->words[1]; \ 7789857Sobrien } \ 7885815Sobrien while (0) 7985815Sobrien 8085815Sobrien#define CHECK_FLAG_COND_NULLIFY() \ 8185815Sobrien do \ 8285815Sobrien { \ 8385815Sobrien if (is_shimm == 0) \ 8485815Sobrien { \ 8585815Sobrien flag = BIT (state->words[0], 8); \ 8685815Sobrien state->nullifyMode = BITS (state->words[0], 5, 6); \ 8785815Sobrien cond = BITS (state->words[0], 0, 4); \ 8885815Sobrien } \ 8985815Sobrien } \ 9085815Sobrien while (0) 9185815Sobrien 9285815Sobrien#define CHECK_COND() \ 9385815Sobrien do \ 9485815Sobrien { \ 9585815Sobrien if (is_shimm == 0) \ 9685815Sobrien cond = BITS (state->words[0], 0, 4); \ 9785815Sobrien } \ 9885815Sobrien while (0) 9985815Sobrien 10085815Sobrien#define CHECK_FIELD(field) \ 10185815Sobrien do \ 10285815Sobrien { \ 10385815Sobrien if (field == 62) \ 10485815Sobrien { \ 10585815Sobrien is_limm++; \ 10685815Sobrien field##isReg = 0; \ 10785815Sobrien PUT_NEXT_WORD_IN (field); \ 10885815Sobrien limm_value = field; \ 10985815Sobrien } \ 11085815Sobrien else if (field > 60) \ 11185815Sobrien { \ 11285815Sobrien field##isReg = 0; \ 11385815Sobrien is_shimm++; \ 11485815Sobrien flag = (field == 61); \ 11585815Sobrien field = FIELDD (state->words[0]); \ 11685815Sobrien } \ 11785815Sobrien } \ 11885815Sobrien while (0) 11985815Sobrien 12085815Sobrien#define CHECK_FIELD_A() \ 12185815Sobrien do \ 12285815Sobrien { \ 12389857Sobrien fieldA = FIELDA (state->words[0]); \ 12485815Sobrien if (fieldA > 60) \ 12585815Sobrien { \ 12685815Sobrien fieldAisReg = 0; \ 12785815Sobrien fieldA = 0; \ 12885815Sobrien } \ 12985815Sobrien } \ 13085815Sobrien while (0) 13185815Sobrien 13285815Sobrien#define CHECK_FIELD_B() \ 13385815Sobrien do \ 13485815Sobrien { \ 13585815Sobrien fieldB = FIELDB (state->words[0]); \ 13685815Sobrien CHECK_FIELD (fieldB); \ 13785815Sobrien } \ 13885815Sobrien while (0) 13985815Sobrien 14085815Sobrien#define CHECK_FIELD_C() \ 14185815Sobrien do \ 14285815Sobrien { \ 14385815Sobrien fieldC = FIELDC (state->words[0]); \ 14485815Sobrien CHECK_FIELD (fieldC); \ 14585815Sobrien } \ 14685815Sobrien while (0) 14785815Sobrien 148218822Sdim#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257)) 149218822Sdim#define IS_REG(x) (field##x##isReg) 150218822Sdim#define WRITE_FORMAT_LB_Rx_RB(x) WRITE_FORMAT (x, "[","]","","") 151218822Sdim#define WRITE_FORMAT_x_COMMA_LB(x) WRITE_FORMAT (x, "",",[","",",[") 152218822Sdim#define WRITE_FORMAT_COMMA_x_RB(x) WRITE_FORMAT (x, ",","]",",","]") 153218822Sdim#define WRITE_FORMAT_x_RB(x) WRITE_FORMAT (x, "","]","","]") 154218822Sdim#define WRITE_FORMAT_COMMA_x(x) WRITE_FORMAT (x, ",","",",","") 155218822Sdim#define WRITE_FORMAT_x_COMMA(x) WRITE_FORMAT (x, "",",","",",") 156218822Sdim#define WRITE_FORMAT_x(x) WRITE_FORMAT (x, "","","","") 15785815Sobrien#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString, \ 15885815Sobrien (IS_REG (x) ? cb1"%r"ca1 : \ 15985815Sobrien usesAuxReg ? cb"%a"ca : \ 16085815Sobrien IS_SMALL (x) ? cb"%d"ca : cb"%h"ca)) 16189857Sobrien#define WRITE_FORMAT_RB() strcat (formatString, "]") 16285815Sobrien#define WRITE_COMMENT(str) (state->comm[state->commNum++] = (str)) 16389857Sobrien#define WRITE_NOP_COMMENT() if (!fieldAisReg && !flag) WRITE_COMMENT ("nop"); 16485815Sobrien 16589857Sobrien#define NEXT_WORD(x) (offset += 4, state->words[x]) 16685815Sobrien 16789857Sobrien#define add_target(x) (state->targets[state->tcnt++] = (x)) 16885815Sobrien 16985815Sobrienstatic char comment_prefix[] = "\t; "; 17085815Sobrien 17185815Sobrienstatic const char * 172218822Sdimcore_reg_name (struct arcDisState * state, int val) 17338889Sjdp{ 17485815Sobrien if (state->coreRegName) 17585815Sobrien return (*state->coreRegName)(state->_this, val); 17685815Sobrien return 0; 17785815Sobrien} 17838889Sjdp 17985815Sobrienstatic const char * 180218822Sdimaux_reg_name (struct arcDisState * state, int val) 18185815Sobrien{ 18285815Sobrien if (state->auxRegName) 18385815Sobrien return (*state->auxRegName)(state->_this, val); 18485815Sobrien return 0; 18585815Sobrien} 18685815Sobrien 18785815Sobrienstatic const char * 188218822Sdimcond_code_name (struct arcDisState * state, int val) 18985815Sobrien{ 19085815Sobrien if (state->condCodeName) 19185815Sobrien return (*state->condCodeName)(state->_this, val); 19285815Sobrien return 0; 19385815Sobrien} 19485815Sobrien 19585815Sobrienstatic const char * 196218822Sdiminstruction_name (struct arcDisState * state, 197218822Sdim int op1, 198218822Sdim int op2, 199218822Sdim int * flags) 20085815Sobrien{ 20185815Sobrien if (state->instName) 20285815Sobrien return (*state->instName)(state->_this, op1, op2, flags); 20385815Sobrien return 0; 20485815Sobrien} 20585815Sobrien 20685815Sobrienstatic void 207218822Sdimmwerror (struct arcDisState * state, const char * msg) 20885815Sobrien{ 20985815Sobrien if (state->err != 0) 21085815Sobrien (*state->err)(state->_this, (msg)); 21185815Sobrien} 21285815Sobrien 21385815Sobrienstatic const char * 214218822Sdimpost_address (struct arcDisState * state, int addr) 21585815Sobrien{ 21685815Sobrien static char id[3 * ARRAY_SIZE (state->addresses)]; 21785815Sobrien int j, i = state->acnt; 21885815Sobrien 21985815Sobrien if (i < ((int) ARRAY_SIZE (state->addresses))) 22038889Sjdp { 22185815Sobrien state->addresses[i] = addr; 22285815Sobrien ++state->acnt; 22385815Sobrien j = i*3; 22485815Sobrien id[j+0] = '@'; 22585815Sobrien id[j+1] = '0'+i; 22685815Sobrien id[j+2] = 0; 22789857Sobrien 22885815Sobrien return id + j; 22938889Sjdp } 23085815Sobrien return ""; 23185815Sobrien} 23238889Sjdp 23389857Sobrienstatic void 234218822Sdimarc_sprintf (struct arcDisState *state, char *buf, const char *format, ...) 23585815Sobrien{ 23689857Sobrien char *bp; 23785815Sobrien const char *p; 23885815Sobrien int size, leading_zero, regMap[2]; 23985815Sobrien long auxNum; 240218822Sdim va_list ap; 24189857Sobrien 242218822Sdim va_start (ap, format); 24389857Sobrien 24489857Sobrien bp = buf; 24585815Sobrien *bp = 0; 24685815Sobrien p = format; 24785815Sobrien auxNum = -1; 24885815Sobrien regMap[0] = 0; 24985815Sobrien regMap[1] = 0; 25089857Sobrien 25189857Sobrien while (1) 25285815Sobrien switch (*p++) 25385815Sobrien { 25489857Sobrien case 0: 25589857Sobrien goto DOCOMM; /* (return) */ 25689857Sobrien default: 25789857Sobrien *bp++ = p[-1]; 25885815Sobrien break; 25985815Sobrien case '%': 26085815Sobrien size = 0; 26185815Sobrien leading_zero = 0; 26285815Sobrien RETRY: ; 26389857Sobrien switch (*p++) 26485815Sobrien { 26585815Sobrien case '0': 26685815Sobrien case '1': 26785815Sobrien case '2': 26885815Sobrien case '3': 26985815Sobrien case '4': 27085815Sobrien case '5': 27185815Sobrien case '6': 27285815Sobrien case '7': 27385815Sobrien case '8': 27485815Sobrien case '9': 27585815Sobrien { 27685815Sobrien /* size. */ 27785815Sobrien size = p[-1] - '0'; 27885815Sobrien if (size == 0) 27985815Sobrien leading_zero = 1; /* e.g. %08x */ 28085815Sobrien while (*p >= '0' && *p <= '9') 28185815Sobrien { 28285815Sobrien size = size * 10 + *p - '0'; 28385815Sobrien p++; 28485815Sobrien } 28585815Sobrien goto RETRY; 28685815Sobrien } 28785815Sobrien#define inc_bp() bp = bp + strlen (bp) 28885815Sobrien 28989857Sobrien case 'h': 29085815Sobrien { 29185815Sobrien unsigned u = va_arg (ap, int); 29285815Sobrien 29385815Sobrien /* Hex. We can change the format to 0x%08x in 29485815Sobrien one place, here, if we wish. 29585815Sobrien We add underscores for easy reading. */ 29689857Sobrien if (u > 65536) 29785815Sobrien sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff); 29889857Sobrien else 29985815Sobrien sprintf (bp, "0x%x", u); 30085815Sobrien inc_bp (); 30189857Sobrien } 30285815Sobrien break; 30389857Sobrien case 'X': case 'x': 30485815Sobrien { 30585815Sobrien int val = va_arg (ap, int); 30685815Sobrien 30789857Sobrien if (size != 0) 30885815Sobrien if (leading_zero) 30985815Sobrien sprintf (bp, "%0*x", size, val); 31085815Sobrien else 31185815Sobrien sprintf (bp, "%*x", size, val); 31285815Sobrien else 31385815Sobrien sprintf (bp, "%x", val); 31485815Sobrien inc_bp (); 31585815Sobrien } 31685815Sobrien break; 31789857Sobrien case 'd': 31885815Sobrien { 31985815Sobrien int val = va_arg (ap, int); 32089857Sobrien 32185815Sobrien if (size != 0) 32285815Sobrien sprintf (bp, "%*d", size, val); 32385815Sobrien else 32485815Sobrien sprintf (bp, "%d", val); 32585815Sobrien inc_bp (); 32685815Sobrien } 32785815Sobrien break; 32889857Sobrien case 'r': 32985815Sobrien { 33085815Sobrien /* Register. */ 33185815Sobrien int val = va_arg (ap, int); 33289857Sobrien 33385815Sobrien#define REG2NAME(num, name) case num: sprintf (bp, ""name); \ 33485815Sobrien regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break; 33589857Sobrien 33689857Sobrien switch (val) 33785815Sobrien { 33885815Sobrien REG2NAME (26, "gp"); 33985815Sobrien REG2NAME (27, "fp"); 34085815Sobrien REG2NAME (28, "sp"); 34185815Sobrien REG2NAME (29, "ilink1"); 34285815Sobrien REG2NAME (30, "ilink2"); 34385815Sobrien REG2NAME (31, "blink"); 34485815Sobrien REG2NAME (60, "lp_count"); 34585815Sobrien default: 34685815Sobrien { 34785815Sobrien const char * ext; 34885815Sobrien 34985815Sobrien ext = core_reg_name (state, val); 35085815Sobrien if (ext) 35185815Sobrien sprintf (bp, "%s", ext); 35285815Sobrien else 35385815Sobrien sprintf (bp,"r%d",val); 35485815Sobrien } 35585815Sobrien break; 35685815Sobrien } 35785815Sobrien inc_bp (); 35885815Sobrien } break; 35989857Sobrien 36089857Sobrien case 'a': 36185815Sobrien { 36285815Sobrien /* Aux Register. */ 36385815Sobrien int val = va_arg (ap, int); 36485815Sobrien 36585815Sobrien#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break; 36685815Sobrien 36789857Sobrien switch (val) 36885815Sobrien { 36985815Sobrien AUXREG2NAME (0x0, "status"); 37085815Sobrien AUXREG2NAME (0x1, "semaphore"); 37185815Sobrien AUXREG2NAME (0x2, "lp_start"); 37285815Sobrien AUXREG2NAME (0x3, "lp_end"); 37385815Sobrien AUXREG2NAME (0x4, "identity"); 37485815Sobrien AUXREG2NAME (0x5, "debug"); 37585815Sobrien default: 37685815Sobrien { 37785815Sobrien const char *ext; 37885815Sobrien 37985815Sobrien ext = aux_reg_name (state, val); 38085815Sobrien if (ext) 38185815Sobrien sprintf (bp, "%s", ext); 38285815Sobrien else 383218822Sdim arc_sprintf (state, bp, "%h", val); 38485815Sobrien } 38585815Sobrien break; 38685815Sobrien } 38785815Sobrien inc_bp (); 38885815Sobrien } 38985815Sobrien break; 39089857Sobrien 39189857Sobrien case 's': 39285815Sobrien { 39385815Sobrien sprintf (bp, "%s", va_arg (ap, char *)); 39485815Sobrien inc_bp (); 39585815Sobrien } 39685815Sobrien break; 39789857Sobrien 39885815Sobrien default: 39985815Sobrien fprintf (stderr, "?? format %c\n", p[-1]); 40085815Sobrien break; 40185815Sobrien } 40285815Sobrien } 40385815Sobrien 40485815Sobrien DOCOMM: *bp = 0; 405218822Sdim va_end (ap); 40685815Sobrien} 40785815Sobrien 40889857Sobrienstatic void 409218822Sdimwrite_comments_(struct arcDisState * state, 410218822Sdim int shimm, 411218822Sdim int is_limm, 412218822Sdim long limm_value) 41385815Sobrien{ 41489857Sobrien if (state->commentBuffer != 0) 41538889Sjdp { 41685815Sobrien int i; 41785815Sobrien 41889857Sobrien if (is_limm) 41985815Sobrien { 42085815Sobrien const char *name = post_address (state, limm_value + shimm); 42185815Sobrien 42285815Sobrien if (*name != 0) 42385815Sobrien WRITE_COMMENT (name); 42485815Sobrien } 42589857Sobrien for (i = 0; i < state->commNum; i++) 42685815Sobrien { 42785815Sobrien if (i == 0) 42885815Sobrien strcpy (state->commentBuffer, comment_prefix); 42985815Sobrien else 43089857Sobrien strcat (state->commentBuffer, ", "); 43189857Sobrien strncat (state->commentBuffer, state->comm[i], 43289857Sobrien sizeof (state->commentBuffer)); 43385815Sobrien } 43438889Sjdp } 43585815Sobrien} 43638889Sjdp 437218822Sdim#define write_comments2(x) write_comments_ (state, x, is_limm, limm_value) 438218822Sdim#define write_comments() write_comments2 (0) 43938889Sjdp 440218822Sdimstatic const char *condName[] = 441218822Sdim{ 44285815Sobrien /* 0..15. */ 44389857Sobrien "" , "z" , "nz" , "p" , "n" , "c" , "nc" , "v" , 44485815Sobrien "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz" 44585815Sobrien}; 44638889Sjdp 44789857Sobrienstatic void 448218822Sdimwrite_instr_name_(struct arcDisState * state, 449218822Sdim const char * instrName, 450218822Sdim int cond, 451218822Sdim int condCodeIsPartOfName, 452218822Sdim int flag, 453218822Sdim int signExtend, 454218822Sdim int addrWriteBack, 455218822Sdim int directMem) 45685815Sobrien{ 45785815Sobrien strcpy (state->instrBuffer, instrName); 45885815Sobrien 45989857Sobrien if (cond > 0) 46038889Sjdp { 46185815Sobrien const char *cc = 0; 46238889Sjdp 46385815Sobrien if (!condCodeIsPartOfName) 46485815Sobrien strcat (state->instrBuffer, "."); 46538889Sjdp 46685815Sobrien if (cond < 16) 46785815Sobrien cc = condName[cond]; 46885815Sobrien else 46985815Sobrien cc = cond_code_name (state, cond); 47038889Sjdp 47185815Sobrien if (!cc) 47285815Sobrien cc = "???"; 47338889Sjdp 47485815Sobrien strcat (state->instrBuffer, cc); 47585815Sobrien } 47638889Sjdp 47785815Sobrien if (flag) 47885815Sobrien strcat (state->instrBuffer, ".f"); 47938889Sjdp 48089857Sobrien switch (state->nullifyMode) 48185815Sobrien { 48285815Sobrien case BR_exec_always: 48385815Sobrien strcat (state->instrBuffer, ".d"); 48485815Sobrien break; 48585815Sobrien case BR_exec_when_jump: 48685815Sobrien strcat (state->instrBuffer, ".jd"); 48785815Sobrien break; 48885815Sobrien } 48938889Sjdp 49085815Sobrien if (signExtend) 49185815Sobrien strcat (state->instrBuffer, ".x"); 49238889Sjdp 49385815Sobrien if (addrWriteBack) 49485815Sobrien strcat (state->instrBuffer, ".a"); 49538889Sjdp 49685815Sobrien if (directMem) 49785815Sobrien strcat (state->instrBuffer, ".di"); 49885815Sobrien} 49985815Sobrien 50085815Sobrien#define write_instr_name() \ 50185815Sobrien do \ 50285815Sobrien { \ 50385815Sobrien write_instr_name_(state, instrName,cond, condCodeIsPartOfName, \ 50485815Sobrien flag, signExtend, addrWriteBack, directMem); \ 50585815Sobrien formatString[0] = '\0'; \ 50685815Sobrien } \ 50785815Sobrien while (0) 50885815Sobrien 509218822Sdimenum 510218822Sdim{ 51189857Sobrien op_LD0 = 0, op_LD1 = 1, op_ST = 2, op_3 = 3, 51285815Sobrien op_BC = 4, op_BLC = 5, op_LPC = 6, op_JC = 7, 51389857Sobrien op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11, 51485815Sobrien op_AND = 12, op_OR = 13, op_BIC = 14, op_XOR = 15 51585815Sobrien}; 51685815Sobrien 51785815Sobrienextern disassemble_info tm_print_insn_info; 51885815Sobrien 51989857Sobrienstatic int 520218822SdimdsmOneArcInst (bfd_vma addr, struct arcDisState * state) 52185815Sobrien{ 52285815Sobrien int condCodeIsPartOfName = 0; 523218822Sdim a4_decoding_class decodingClass; 52485815Sobrien const char * instrName; 52585815Sobrien int repeatsOp = 0; 52685815Sobrien int fieldAisReg = 1; 52785815Sobrien int fieldBisReg = 1; 52885815Sobrien int fieldCisReg = 1; 52985815Sobrien int fieldA; 53085815Sobrien int fieldB; 53185815Sobrien int fieldC = 0; 53285815Sobrien int flag = 0; 53385815Sobrien int cond = 0; 53485815Sobrien int is_shimm = 0; 53585815Sobrien int is_limm = 0; 53685815Sobrien long limm_value = 0; 53785815Sobrien int signExtend = 0; 53885815Sobrien int addrWriteBack = 0; 53985815Sobrien int directMem = 0; 54085815Sobrien int is_linked = 0; 54185815Sobrien int offset = 0; 54285815Sobrien int usesAuxReg = 0; 54385815Sobrien int flags; 54485815Sobrien int ignoreFirstOpd; 54585815Sobrien char formatString[60]; 54689857Sobrien 54785815Sobrien state->instructionLen = 4; 54885815Sobrien state->nullifyMode = BR_exec_when_no_jump; 54985815Sobrien state->opWidth = 12; 55085815Sobrien state->isBranch = 0; 55189857Sobrien 55285815Sobrien state->_mem_load = 0; 55385815Sobrien state->_ea_present = 0; 55485815Sobrien state->_load_len = 0; 55585815Sobrien state->ea_reg1 = no_reg; 55685815Sobrien state->ea_reg2 = no_reg; 55785815Sobrien state->_offset = 0; 55889857Sobrien 55985815Sobrien if (! NEXT_WORD (0)) 56085815Sobrien return 0; 56189857Sobrien 56285815Sobrien state->_opcode = OPCODE (state->words[0]); 56385815Sobrien instrName = 0; 564218822Sdim decodingClass = CLASS_A4_ARITH; /* default! */ 56585815Sobrien repeatsOp = 0; 56685815Sobrien condCodeIsPartOfName=0; 56785815Sobrien state->commNum = 0; 56885815Sobrien state->tcnt = 0; 56985815Sobrien state->acnt = 0; 57085815Sobrien state->flow = noflow; 57185815Sobrien ignoreFirstOpd = 0; 57285815Sobrien 57385815Sobrien if (state->commentBuffer) 57485815Sobrien state->commentBuffer[0] = '\0'; 57585815Sobrien 57689857Sobrien switch (state->_opcode) 57785815Sobrien { 57889857Sobrien case op_LD0: 57989857Sobrien switch (BITS (state->words[0],1,2)) 58038889Sjdp { 58185815Sobrien case 0: 58285815Sobrien instrName = "ld"; 58385815Sobrien state->_load_len = 4; 58485815Sobrien break; 58585815Sobrien case 1: 58685815Sobrien instrName = "ldb"; 58785815Sobrien state->_load_len = 1; 58885815Sobrien break; 58985815Sobrien case 2: 59085815Sobrien instrName = "ldw"; 59185815Sobrien state->_load_len = 2; 59285815Sobrien break; 59385815Sobrien default: 59489857Sobrien instrName = "??? (0[3])"; 59585815Sobrien state->flow = invalid_instr; 59685815Sobrien break; 59785815Sobrien } 598218822Sdim decodingClass = CLASS_A4_LD0; 59985815Sobrien break; 60089857Sobrien 60189857Sobrien case op_LD1: 60289857Sobrien if (BIT (state->words[0],13)) 60385815Sobrien { 60489857Sobrien instrName = "lr"; 605218822Sdim decodingClass = CLASS_A4_LR; 60685815Sobrien } 60789857Sobrien else 60885815Sobrien { 609218822Sdim switch (BITS (state->words[0], 10, 11)) 61038889Sjdp { 61185815Sobrien case 0: 61285815Sobrien instrName = "ld"; 61385815Sobrien state->_load_len = 4; 61485815Sobrien break; 61585815Sobrien case 1: 61685815Sobrien instrName = "ldb"; 61785815Sobrien state->_load_len = 1; 61885815Sobrien break; 61985815Sobrien case 2: 62085815Sobrien instrName = "ldw"; 62185815Sobrien state->_load_len = 2; 62285815Sobrien break; 62385815Sobrien default: 62489857Sobrien instrName = "??? (1[3])"; 62585815Sobrien state->flow = invalid_instr; 62685815Sobrien break; 62738889Sjdp } 628218822Sdim decodingClass = CLASS_A4_LD1; 62938889Sjdp } 63085815Sobrien break; 63189857Sobrien 63285815Sobrien case op_ST: 633218822Sdim if (BIT (state->words[0], 25)) 63438889Sjdp { 63585815Sobrien instrName = "sr"; 636218822Sdim decodingClass = CLASS_A4_SR; 63785815Sobrien } 63889857Sobrien else 63985815Sobrien { 640218822Sdim switch (BITS (state->words[0], 22, 23)) 64138889Sjdp { 64285815Sobrien case 0: 64385815Sobrien instrName = "st"; 64485815Sobrien break; 64585815Sobrien case 1: 64685815Sobrien instrName = "stb"; 64785815Sobrien break; 64885815Sobrien case 2: 64985815Sobrien instrName = "stw"; 65085815Sobrien break; 65185815Sobrien default: 65289857Sobrien instrName = "??? (2[3])"; 65385815Sobrien state->flow = invalid_instr; 65485815Sobrien break; 65538889Sjdp } 656218822Sdim decodingClass = CLASS_A4_ST; 65785815Sobrien } 65885815Sobrien break; 65989857Sobrien 66085815Sobrien case op_3: 661218822Sdim decodingClass = CLASS_A4_OP3_GENERAL; /* default for opcode 3... */ 66289857Sobrien switch (FIELDC (state->words[0])) 66385815Sobrien { 66485815Sobrien case 0: 66589857Sobrien instrName = "flag"; 666218822Sdim decodingClass = CLASS_A4_FLAG; 66785815Sobrien break; 66885815Sobrien case 1: 66985815Sobrien instrName = "asr"; 67085815Sobrien break; 67185815Sobrien case 2: 67285815Sobrien instrName = "lsr"; 67385815Sobrien break; 67485815Sobrien case 3: 67585815Sobrien instrName = "ror"; 67685815Sobrien break; 67785815Sobrien case 4: 67885815Sobrien instrName = "rrc"; 67985815Sobrien break; 68085815Sobrien case 5: 68185815Sobrien instrName = "sexb"; 68285815Sobrien break; 68385815Sobrien case 6: 68485815Sobrien instrName = "sexw"; 68585815Sobrien break; 68685815Sobrien case 7: 68785815Sobrien instrName = "extb"; 68885815Sobrien break; 68985815Sobrien case 8: 69085815Sobrien instrName = "extw"; 69185815Sobrien break; 69289857Sobrien case 0x3f: 69385815Sobrien { 694218822Sdim decodingClass = CLASS_A4_OP3_SUBOPC3F; 695218822Sdim switch (FIELDD (state->words[0])) 69685815Sobrien { 69785815Sobrien case 0: 69885815Sobrien instrName = "brk"; 69985815Sobrien break; 70085815Sobrien case 1: 70185815Sobrien instrName = "sleep"; 70285815Sobrien break; 70385815Sobrien case 2: 70485815Sobrien instrName = "swi"; 70585815Sobrien break; 70685815Sobrien default: 70785815Sobrien instrName = "???"; 70885815Sobrien state->flow=invalid_instr; 70985815Sobrien break; 71085815Sobrien } 71185815Sobrien } 71285815Sobrien break; 71389857Sobrien 71485815Sobrien /* ARC Extension Library Instructions 71585815Sobrien NOTE: We assume that extension codes are these instrs. */ 71685815Sobrien default: 71785815Sobrien instrName = instruction_name (state, 71885815Sobrien state->_opcode, 71985815Sobrien FIELDC (state->words[0]), 72089857Sobrien &flags); 72185815Sobrien if (!instrName) 72238889Sjdp { 72385815Sobrien instrName = "???"; 72485815Sobrien state->flow = invalid_instr; 72538889Sjdp } 72685815Sobrien if (flags & IGNORE_FIRST_OPD) 72785815Sobrien ignoreFirstOpd = 1; 72885815Sobrien break; 72985815Sobrien } 73085815Sobrien break; 73138889Sjdp 73285815Sobrien case op_BC: 73389857Sobrien instrName = "b"; 73485815Sobrien case op_BLC: 73585815Sobrien if (!instrName) 73689857Sobrien instrName = "bl"; 73785815Sobrien case op_LPC: 73885815Sobrien if (!instrName) 73989857Sobrien instrName = "lp"; 74085815Sobrien case op_JC: 74185815Sobrien if (!instrName) 74285815Sobrien { 74389857Sobrien if (BITS (state->words[0],9,9)) 74438889Sjdp { 74589857Sobrien instrName = "jl"; 74685815Sobrien is_linked = 1; 74738889Sjdp } 74889857Sobrien else 74938889Sjdp { 75089857Sobrien instrName = "j"; 75185815Sobrien is_linked = 0; 75238889Sjdp } 75385815Sobrien } 75485815Sobrien condCodeIsPartOfName = 1; 755218822Sdim decodingClass = ((state->_opcode == op_JC) ? CLASS_A4_JC : CLASS_A4_BRANCH ); 75685815Sobrien state->isBranch = 1; 75785815Sobrien break; 75889857Sobrien 75985815Sobrien case op_ADD: 76085815Sobrien case op_ADC: 76185815Sobrien case op_AND: 76285815Sobrien repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0])); 76338889Sjdp 76489857Sobrien switch (state->_opcode) 76585815Sobrien { 76685815Sobrien case op_ADD: 76785815Sobrien instrName = (repeatsOp ? "asl" : "add"); 76885815Sobrien break; 76985815Sobrien case op_ADC: 77085815Sobrien instrName = (repeatsOp ? "rlc" : "adc"); 77185815Sobrien break; 77285815Sobrien case op_AND: 77385815Sobrien instrName = (repeatsOp ? "mov" : "and"); 77485815Sobrien break; 77585815Sobrien } 77685815Sobrien break; 77789857Sobrien 77885815Sobrien case op_SUB: instrName = "sub"; 77985815Sobrien break; 78085815Sobrien case op_SBC: instrName = "sbc"; 78185815Sobrien break; 78285815Sobrien case op_OR: instrName = "or"; 78385815Sobrien break; 78485815Sobrien case op_BIC: instrName = "bic"; 78585815Sobrien break; 78685815Sobrien 78785815Sobrien case op_XOR: 78885815Sobrien if (state->words[0] == 0x7fffffff) 78985815Sobrien { 790218822Sdim /* NOP encoded as xor -1, -1, -1. */ 79185815Sobrien instrName = "nop"; 792218822Sdim decodingClass = CLASS_A4_OP3_SUBOPC3F; 79385815Sobrien } 79489857Sobrien else 79585815Sobrien instrName = "xor"; 79685815Sobrien break; 79789857Sobrien 79885815Sobrien default: 79985815Sobrien instrName = instruction_name (state,state->_opcode,0,&flags); 80085815Sobrien /* if (instrName) printf("FLAGS=0x%x\n", flags); */ 80185815Sobrien if (!instrName) 80285815Sobrien { 80385815Sobrien instrName = "???"; 80485815Sobrien state->flow=invalid_instr; 80585815Sobrien } 80685815Sobrien if (flags & IGNORE_FIRST_OPD) 80785815Sobrien ignoreFirstOpd = 1; 80885815Sobrien break; 80985815Sobrien } 81089857Sobrien 81185815Sobrien fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now. */ 81285815Sobrien flag = cond = is_shimm = is_limm = 0; 81385815Sobrien state->nullifyMode = BR_exec_when_no_jump; /* 0 */ 81485815Sobrien signExtend = addrWriteBack = directMem = 0; 81585815Sobrien usesAuxReg = 0; 81689857Sobrien 81789857Sobrien switch (decodingClass) 81885815Sobrien { 819218822Sdim case CLASS_A4_ARITH: 82085815Sobrien CHECK_FIELD_A (); 82185815Sobrien CHECK_FIELD_B (); 82285815Sobrien if (!repeatsOp) 82385815Sobrien CHECK_FIELD_C (); 82485815Sobrien CHECK_FLAG_COND_NULLIFY (); 82589857Sobrien 82685815Sobrien write_instr_name (); 82789857Sobrien if (!ignoreFirstOpd) 82885815Sobrien { 82985815Sobrien WRITE_FORMAT_x (A); 83085815Sobrien WRITE_FORMAT_COMMA_x (B); 83185815Sobrien if (!repeatsOp) 83285815Sobrien WRITE_FORMAT_COMMA_x (C); 83385815Sobrien WRITE_NOP_COMMENT (); 834218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 83589857Sobrien fieldA, fieldB, fieldC); 83685815Sobrien } 83789857Sobrien else 83885815Sobrien { 83985815Sobrien WRITE_FORMAT_x (B); 84085815Sobrien if (!repeatsOp) 84185815Sobrien WRITE_FORMAT_COMMA_x (C); 842218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 84389857Sobrien fieldB, fieldC); 84485815Sobrien } 84585815Sobrien write_comments (); 84685815Sobrien break; 84789857Sobrien 848218822Sdim case CLASS_A4_OP3_GENERAL: 84985815Sobrien CHECK_FIELD_A (); 85085815Sobrien CHECK_FIELD_B (); 85185815Sobrien CHECK_FLAG_COND_NULLIFY (); 85289857Sobrien 85385815Sobrien write_instr_name (); 85489857Sobrien if (!ignoreFirstOpd) 85585815Sobrien { 85685815Sobrien WRITE_FORMAT_x (A); 85785815Sobrien WRITE_FORMAT_COMMA_x (B); 85885815Sobrien WRITE_NOP_COMMENT (); 859218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 86089857Sobrien fieldA, fieldB); 86185815Sobrien } 86289857Sobrien else 86385815Sobrien { 86485815Sobrien WRITE_FORMAT_x (B); 865218822Sdim arc_sprintf (state, state->operandBuffer, formatString, fieldB); 86685815Sobrien } 86785815Sobrien write_comments (); 86885815Sobrien break; 86989857Sobrien 870218822Sdim case CLASS_A4_FLAG: 87185815Sobrien CHECK_FIELD_B (); 87285815Sobrien CHECK_FLAG_COND_NULLIFY (); 873218822Sdim flag = 0; /* This is the FLAG instruction -- it's redundant. */ 87489857Sobrien 87585815Sobrien write_instr_name (); 87685815Sobrien WRITE_FORMAT_x (B); 877218822Sdim arc_sprintf (state, state->operandBuffer, formatString, fieldB); 87885815Sobrien write_comments (); 87985815Sobrien break; 88089857Sobrien 881218822Sdim case CLASS_A4_BRANCH: 88285815Sobrien fieldA = BITS (state->words[0],7,26) << 2; 883218822Sdim fieldA = (fieldA << 10) >> 10; /* Make it signed. */ 88485815Sobrien fieldA += addr + 4; 88585815Sobrien CHECK_FLAG_COND_NULLIFY (); 88685815Sobrien flag = 0; 88789857Sobrien 88885815Sobrien write_instr_name (); 88985815Sobrien /* This address could be a label we know. Convert it. */ 89089857Sobrien if (state->_opcode != op_LPC /* LP */) 89185815Sobrien { 89289857Sobrien add_target (fieldA); /* For debugger. */ 89389857Sobrien state->flow = state->_opcode == op_BLC /* BL */ 89489857Sobrien ? direct_call 89589857Sobrien : direct_jump; 89689857Sobrien /* indirect calls are achieved by "lr blink,[status]; 89789857Sobrien lr dest<- func addr; j [dest]" */ 89889857Sobrien } 89989857Sobrien 900218822Sdim strcat (formatString, "%s"); /* Address/label name. */ 901218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 90289857Sobrien post_address (state, fieldA)); 90385815Sobrien write_comments (); 90485815Sobrien break; 90589857Sobrien 906218822Sdim case CLASS_A4_JC: 90785815Sobrien /* For op_JC -- jump to address specified. 90885815Sobrien Also covers jump and link--bit 9 of the instr. word 90985815Sobrien selects whether linked, thus "is_linked" is set above. */ 91085815Sobrien fieldA = 0; 91185815Sobrien CHECK_FIELD_B (); 91285815Sobrien CHECK_FLAG_COND_NULLIFY (); 91389857Sobrien 91489857Sobrien if (!fieldBisReg) 91585815Sobrien { 91685815Sobrien fieldAisReg = 0; 917218822Sdim fieldA = (fieldB >> 25) & 0x7F; /* Flags. */ 91885815Sobrien fieldB = (fieldB & 0xFFFFFF) << 2; 91985815Sobrien state->flow = is_linked ? direct_call : direct_jump; 92085815Sobrien add_target (fieldB); 921218822Sdim /* Screwy JLcc requires .jd mode to execute correctly 922218822Sdim but we pretend it is .nd (no delay slot). */ 92385815Sobrien if (is_linked && state->nullifyMode == BR_exec_when_jump) 92485815Sobrien state->nullifyMode = BR_exec_when_no_jump; 92585815Sobrien } 92689857Sobrien else 92785815Sobrien { 92885815Sobrien state->flow = is_linked ? indirect_call : indirect_jump; 92985815Sobrien /* We should also treat this as indirect call if NOT linked 930218822Sdim but the preceding instruction was a "lr blink,[status]" 931218822Sdim and we have a delay slot with "add blink,blink,2". 932218822Sdim For now we can't detect such. */ 93385815Sobrien state->register_for_indirect_jump = fieldB; 93485815Sobrien } 93589857Sobrien 93685815Sobrien write_instr_name (); 93789857Sobrien strcat (formatString, 938218822Sdim IS_REG (B) ? "[%r]" : "%s"); /* Address/label name. */ 93989857Sobrien if (fieldA != 0) 94085815Sobrien { 94185815Sobrien fieldAisReg = 0; 94285815Sobrien WRITE_FORMAT_COMMA_x (A); 94385815Sobrien } 94485815Sobrien if (IS_REG (B)) 945218822Sdim arc_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA); 94685815Sobrien else 947218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 94885815Sobrien post_address (state, fieldB), fieldA); 94985815Sobrien write_comments (); 95085815Sobrien break; 95189857Sobrien 952218822Sdim case CLASS_A4_LD0: 95385815Sobrien /* LD instruction. 95485815Sobrien B and C can be regs, or one (both?) can be limm. */ 95585815Sobrien CHECK_FIELD_A (); 95685815Sobrien CHECK_FIELD_B (); 95785815Sobrien CHECK_FIELD_C (); 95885815Sobrien if (dbg) 95985815Sobrien printf ("5:b reg %d %d c reg %d %d \n", 96085815Sobrien fieldBisReg,fieldB,fieldCisReg,fieldC); 96185815Sobrien state->_offset = 0; 96285815Sobrien state->_ea_present = 1; 96385815Sobrien if (fieldBisReg) 96485815Sobrien state->ea_reg1 = fieldB; 96585815Sobrien else 96685815Sobrien state->_offset += fieldB; 96785815Sobrien if (fieldCisReg) 96885815Sobrien state->ea_reg2 = fieldC; 96985815Sobrien else 97085815Sobrien state->_offset += fieldC; 97185815Sobrien state->_mem_load = 1; 97289857Sobrien 973218822Sdim directMem = BIT (state->words[0], 5); 974218822Sdim addrWriteBack = BIT (state->words[0], 3); 975218822Sdim signExtend = BIT (state->words[0], 0); 97689857Sobrien 97785815Sobrien write_instr_name (); 97885815Sobrien WRITE_FORMAT_x_COMMA_LB(A); 97985815Sobrien if (fieldBisReg || fieldB != 0) 98085815Sobrien WRITE_FORMAT_x_COMMA (B); 98185815Sobrien else 98285815Sobrien fieldB = fieldC; 98389857Sobrien 98485815Sobrien WRITE_FORMAT_x_RB (C); 985218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 98689857Sobrien fieldA, fieldB, fieldC); 98785815Sobrien write_comments (); 98885815Sobrien break; 98989857Sobrien 990218822Sdim case CLASS_A4_LD1: 99185815Sobrien /* LD instruction. */ 99285815Sobrien CHECK_FIELD_B (); 99385815Sobrien CHECK_FIELD_A (); 99485815Sobrien fieldC = FIELDD (state->words[0]); 99589857Sobrien 99685815Sobrien if (dbg) 99785815Sobrien printf ("6:b reg %d %d c 0x%x \n", 99885815Sobrien fieldBisReg, fieldB, fieldC); 99985815Sobrien state->_ea_present = 1; 100085815Sobrien state->_offset = fieldC; 100185815Sobrien state->_mem_load = 1; 100285815Sobrien if (fieldBisReg) 100385815Sobrien state->ea_reg1 = fieldB; 1004218822Sdim /* Field B is either a shimm (same as fieldC) or limm (different!) 100585815Sobrien Say ea is not present, so only one of us will do the name lookup. */ 100685815Sobrien else 100785815Sobrien state->_offset += fieldB, state->_ea_present = 0; 100889857Sobrien 100985815Sobrien directMem = BIT (state->words[0],14); 101085815Sobrien addrWriteBack = BIT (state->words[0],12); 101185815Sobrien signExtend = BIT (state->words[0],9); 101289857Sobrien 101385815Sobrien write_instr_name (); 101485815Sobrien WRITE_FORMAT_x_COMMA_LB (A); 101589857Sobrien if (!fieldBisReg) 101685815Sobrien { 101785815Sobrien fieldB = state->_offset; 101885815Sobrien WRITE_FORMAT_x_RB (B); 101985815Sobrien } 102089857Sobrien else 102185815Sobrien { 102285815Sobrien WRITE_FORMAT_x (B); 102389857Sobrien if (fieldC != 0 && !BIT (state->words[0],13)) 102438889Sjdp { 102585815Sobrien fieldCisReg = 0; 102685815Sobrien WRITE_FORMAT_COMMA_x_RB (C); 102738889Sjdp } 102838889Sjdp else 102985815Sobrien WRITE_FORMAT_RB (); 103038889Sjdp } 1031218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 103289857Sobrien fieldA, fieldB, fieldC); 103385815Sobrien write_comments (); 103485815Sobrien break; 103589857Sobrien 1036218822Sdim case CLASS_A4_ST: 103785815Sobrien /* ST instruction. */ 103885815Sobrien CHECK_FIELD_B(); 103985815Sobrien CHECK_FIELD_C(); 104085815Sobrien fieldA = FIELDD(state->words[0]); /* shimm */ 104189857Sobrien 104285815Sobrien /* [B,A offset] */ 104385815Sobrien if (dbg) printf("7:b reg %d %x off %x\n", 104489857Sobrien fieldBisReg,fieldB,fieldA); 104585815Sobrien state->_ea_present = 1; 104685815Sobrien state->_offset = fieldA; 104785815Sobrien if (fieldBisReg) 104885815Sobrien state->ea_reg1 = fieldB; 1049218822Sdim /* Field B is either a shimm (same as fieldA) or limm (different!) 105085815Sobrien Say ea is not present, so only one of us will do the name lookup. 105185815Sobrien (for is_limm we do the name translation here). */ 105289857Sobrien else 105385815Sobrien state->_offset += fieldB, state->_ea_present = 0; 105489857Sobrien 1055218822Sdim directMem = BIT (state->words[0], 26); 1056218822Sdim addrWriteBack = BIT (state->words[0], 24); 105789857Sobrien 1058218822Sdim write_instr_name (); 105985815Sobrien WRITE_FORMAT_x_COMMA_LB(C); 106089857Sobrien 106189857Sobrien if (!fieldBisReg) 106285815Sobrien { 106385815Sobrien fieldB = state->_offset; 1064218822Sdim WRITE_FORMAT_x_RB (B); 106585815Sobrien } 106689857Sobrien else 106785815Sobrien { 1068218822Sdim WRITE_FORMAT_x (B); 106989857Sobrien if (fieldBisReg && fieldA != 0) 107085815Sobrien { 107185815Sobrien fieldAisReg = 0; 107285815Sobrien WRITE_FORMAT_COMMA_x_RB(A); 107385815Sobrien } 107485815Sobrien else 107585815Sobrien WRITE_FORMAT_RB(); 107685815Sobrien } 1077218822Sdim arc_sprintf (state, state->operandBuffer, formatString, 107889857Sobrien fieldC, fieldB, fieldA); 1079218822Sdim write_comments2 (fieldA); 108085815Sobrien break; 1081218822Sdim 1082218822Sdim case CLASS_A4_SR: 108385815Sobrien /* SR instruction */ 108485815Sobrien CHECK_FIELD_B(); 108585815Sobrien CHECK_FIELD_C(); 108689857Sobrien 1087218822Sdim write_instr_name (); 108885815Sobrien WRITE_FORMAT_x_COMMA_LB(C); 108985815Sobrien /* Try to print B as an aux reg if it is not a core reg. */ 109085815Sobrien usesAuxReg = 1; 1091218822Sdim WRITE_FORMAT_x (B); 1092218822Sdim WRITE_FORMAT_RB (); 1093218822Sdim arc_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB); 1094218822Sdim write_comments (); 109585815Sobrien break; 109689857Sobrien 1097218822Sdim case CLASS_A4_OP3_SUBOPC3F: 1098218822Sdim write_instr_name (); 109985815Sobrien state->operandBuffer[0] = '\0'; 110085815Sobrien break; 110189857Sobrien 1102218822Sdim case CLASS_A4_LR: 110385815Sobrien /* LR instruction */ 1104218822Sdim CHECK_FIELD_A (); 1105218822Sdim CHECK_FIELD_B (); 110689857Sobrien 1107218822Sdim write_instr_name (); 1108218822Sdim WRITE_FORMAT_x_COMMA_LB (A); 110985815Sobrien /* Try to print B as an aux reg if it is not a core reg. */ 111085815Sobrien usesAuxReg = 1; 1111218822Sdim WRITE_FORMAT_x (B); 1112218822Sdim WRITE_FORMAT_RB (); 1113218822Sdim arc_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB); 1114218822Sdim write_comments (); 111585815Sobrien break; 111689857Sobrien 111785815Sobrien default: 111885815Sobrien mwerror (state, "Bad decoding class in ARC disassembler"); 111985815Sobrien break; 112038889Sjdp } 112189857Sobrien 112285815Sobrien state->_cond = cond; 112385815Sobrien return state->instructionLen = offset; 112485815Sobrien} 112538889Sjdp 112685815Sobrien 112785815Sobrien/* Returns the name the user specified core extension register. */ 1128218822Sdim 112985815Sobrienstatic const char * 1130218822Sdim_coreRegName(void * arg ATTRIBUTE_UNUSED, int regval) 113185815Sobrien{ 113285815Sobrien return arcExtMap_coreRegName (regval); 113338889Sjdp} 113438889Sjdp 113585815Sobrien/* Returns the name the user specified AUX extension register. */ 1136218822Sdim 113785815Sobrienstatic const char * 113885815Sobrien_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval) 113985815Sobrien{ 114089857Sobrien return arcExtMap_auxRegName(regval); 114185815Sobrien} 114238889Sjdp 1143218822Sdim/* Returns the name the user specified condition code name. */ 114485815Sobrien 114585815Sobrienstatic const char * 114685815Sobrien_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval) 114738889Sjdp{ 114889857Sobrien return arcExtMap_condCodeName(regval); 114938889Sjdp} 115038889Sjdp 115185815Sobrien/* Returns the name the user specified extension instruction. */ 1152218822Sdim 115385815Sobrienstatic const char * 115485815Sobrien_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags) 115538889Sjdp{ 115689857Sobrien return arcExtMap_instName(majop, minop, flags); 115738889Sjdp} 115838889Sjdp 115985815Sobrien/* Decode an instruction returning the size of the instruction 116085815Sobrien in bytes or zero if unrecognized. */ 1161218822Sdim 116238889Sjdpstatic int 1163218822SdimdecodeInstr (bfd_vma address, /* Address of this instruction. */ 1164218822Sdim disassemble_info * info) 116538889Sjdp{ 116685815Sobrien int status; 116785815Sobrien bfd_byte buffer[4]; 1168218822Sdim struct arcDisState s; /* ARC Disassembler state. */ 1169218822Sdim void *stream = info->stream; /* Output stream. */ 117089857Sobrien fprintf_ftype func = info->fprintf_func; 117185815Sobrien int bytes; 117289857Sobrien 117385815Sobrien memset (&s, 0, sizeof(struct arcDisState)); 117489857Sobrien 117585815Sobrien /* read first instruction */ 117685815Sobrien status = (*info->read_memory_func) (address, buffer, 4, info); 117785815Sobrien if (status != 0) 117885815Sobrien { 117985815Sobrien (*info->memory_error_func) (status, address, info); 118085815Sobrien return 0; 118185815Sobrien } 118285815Sobrien if (info->endian == BFD_ENDIAN_LITTLE) 118385815Sobrien s.words[0] = bfd_getl32(buffer); 118485815Sobrien else 118585815Sobrien s.words[0] = bfd_getb32(buffer); 1186218822Sdim /* Always read second word in case of limm. */ 118785815Sobrien 1188218822Sdim /* We ignore the result since last insn may not have a limm. */ 118985815Sobrien status = (*info->read_memory_func) (address + 4, buffer, 4, info); 119085815Sobrien if (info->endian == BFD_ENDIAN_LITTLE) 119185815Sobrien s.words[1] = bfd_getl32(buffer); 119285815Sobrien else 119385815Sobrien s.words[1] = bfd_getb32(buffer); 119485815Sobrien 119585815Sobrien s._this = &s; 119685815Sobrien s.coreRegName = _coreRegName; 119785815Sobrien s.auxRegName = _auxRegName; 119885815Sobrien s.condCodeName = _condCodeName; 119985815Sobrien s.instName = _instName; 120085815Sobrien 1201218822Sdim /* Disassemble. */ 1202218822Sdim bytes = dsmOneArcInst (address, (void *)& s); 120385815Sobrien 1204218822Sdim /* Display the disassembly instruction. */ 1205218822Sdim (*func) (stream, "%08lx ", s.words[0]); 120685815Sobrien (*func) (stream, " "); 120785815Sobrien (*func) (stream, "%-10s ", s.instrBuffer); 120889857Sobrien 1209218822Sdim if (__TRANSLATION_REQUIRED (s)) 121085815Sobrien { 121185815Sobrien bfd_vma addr = s.addresses[s.operandBuffer[1] - '0']; 1212218822Sdim 121385815Sobrien (*info->print_address_func) ((bfd_vma) addr, info); 121485815Sobrien (*func) (stream, "\n"); 121585815Sobrien } 121685815Sobrien else 121785815Sobrien (*func) (stream, "%s",s.operandBuffer); 1218218822Sdim 121985815Sobrien return s.instructionLen; 122038889Sjdp} 122185815Sobrien 122285815Sobrien/* Return the print_insn function to use. 122385815Sobrien Side effect: load (possibly empty) extension section */ 122485815Sobrien 122585815Sobriendisassembler_ftype 122685815Sobrienarc_get_disassembler (void *ptr) 122785815Sobrien{ 122885815Sobrien if (ptr) 122985815Sobrien build_ARC_extmap (ptr); 123085815Sobrien return decodeInstr; 123185815Sobrien} 1232