arc-dis.c revision 89857
138889Sjdp/* Instruction printing code for the ARC. 285815Sobrien Copyright 1994, 1995, 1997, 1998, 2000, 2001 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 1885815Sobrien Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 1938889Sjdp 2085815Sobrien#include <ansidecl.h> 2185815Sobrien#include <libiberty.h> 2238889Sjdp#include "dis-asm.h" 2338889Sjdp#include "opcode/arc.h" 2438889Sjdp#include "elf-bfd.h" 2538889Sjdp#include "elf/arc.h" 2685815Sobrien#include <string.h> 2760484Sobrien#include "opintl.h" 2838889Sjdp 2985815Sobrien#include <stdarg.h> 3085815Sobrien#include "arc-dis.h" 3185815Sobrien#include "arc-ext.h" 3238889Sjdp 3385815Sobrien#ifndef dbg 3485815Sobrien#define dbg (0) 3585815Sobrien#endif 3638889Sjdp 3789857Sobrien#define BIT(word,n) ((word) & (1 << n)) 3889857Sobrien#define BITS(word,s,e) (((word) << (31 - e)) >> (s + (31 - e))) 3989857Sobrien#define OPCODE(word) (BITS ((word), 27, 31)) 4089857Sobrien#define FIELDA(word) (BITS ((word), 21, 26)) 4189857Sobrien#define FIELDB(word) (BITS ((word), 15, 20)) 4289857Sobrien#define FIELDC(word) (BITS ((word), 9, 14)) 4338889Sjdp 4485815Sobrien/* FIELD D is signed in all of its uses, so we make sure argument is 4585815Sobrien treated as signed for bit shifting purposes: */ 4689857Sobrien#define FIELDD(word) (BITS (((signed int)word), 0, 8)) 4785815Sobrien 4889857Sobrien#define PUT_NEXT_WORD_IN(a) \ 4989857Sobrien do \ 5089857Sobrien { \ 5189857Sobrien if (is_limm == 1 && !NEXT_WORD (1)) \ 5289857Sobrien mwerror (state, _("Illegal limm reference in last instruction!\n")); \ 5389857Sobrien a = state->words[1]; \ 5489857Sobrien } \ 5585815Sobrien while (0) 5685815Sobrien 5785815Sobrien#define CHECK_FLAG_COND_NULLIFY() \ 5885815Sobrien do \ 5985815Sobrien { \ 6085815Sobrien if (is_shimm == 0) \ 6185815Sobrien { \ 6285815Sobrien flag = BIT (state->words[0], 8); \ 6385815Sobrien state->nullifyMode = BITS (state->words[0], 5, 6); \ 6485815Sobrien cond = BITS (state->words[0], 0, 4); \ 6585815Sobrien } \ 6685815Sobrien } \ 6785815Sobrien while (0) 6885815Sobrien 6985815Sobrien#define CHECK_COND() \ 7085815Sobrien do \ 7185815Sobrien { \ 7285815Sobrien if (is_shimm == 0) \ 7385815Sobrien cond = BITS (state->words[0], 0, 4); \ 7485815Sobrien } \ 7585815Sobrien while (0) 7685815Sobrien 7785815Sobrien#define CHECK_FIELD(field) \ 7885815Sobrien do \ 7985815Sobrien { \ 8085815Sobrien if (field == 62) \ 8185815Sobrien { \ 8285815Sobrien is_limm++; \ 8385815Sobrien field##isReg = 0; \ 8485815Sobrien PUT_NEXT_WORD_IN (field); \ 8585815Sobrien limm_value = field; \ 8685815Sobrien } \ 8785815Sobrien else if (field > 60) \ 8885815Sobrien { \ 8985815Sobrien field##isReg = 0; \ 9085815Sobrien is_shimm++; \ 9185815Sobrien flag = (field == 61); \ 9285815Sobrien field = FIELDD (state->words[0]); \ 9385815Sobrien } \ 9485815Sobrien } \ 9585815Sobrien while (0) 9685815Sobrien 9785815Sobrien#define CHECK_FIELD_A() \ 9885815Sobrien do \ 9985815Sobrien { \ 10089857Sobrien fieldA = FIELDA (state->words[0]); \ 10185815Sobrien if (fieldA > 60) \ 10285815Sobrien { \ 10385815Sobrien fieldAisReg = 0; \ 10485815Sobrien fieldA = 0; \ 10585815Sobrien } \ 10685815Sobrien } \ 10785815Sobrien while (0) 10885815Sobrien 10985815Sobrien#define CHECK_FIELD_B() \ 11085815Sobrien do \ 11185815Sobrien { \ 11285815Sobrien fieldB = FIELDB (state->words[0]); \ 11385815Sobrien CHECK_FIELD (fieldB); \ 11485815Sobrien } \ 11585815Sobrien while (0) 11685815Sobrien 11785815Sobrien#define CHECK_FIELD_C() \ 11885815Sobrien do \ 11985815Sobrien { \ 12085815Sobrien fieldC = FIELDC (state->words[0]); \ 12185815Sobrien CHECK_FIELD (fieldC); \ 12285815Sobrien } \ 12385815Sobrien while (0) 12485815Sobrien 12585815Sobrien#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257)) 12685815Sobrien#define IS_REG(x) (field##x##isReg) 12785815Sobrien#define WRITE_FORMAT_LB_Rx_RB(x) WRITE_FORMAT(x,"[","]","","") 12885815Sobrien#define WRITE_FORMAT_x_COMMA_LB(x) WRITE_FORMAT(x,"",",[","",",[") 12985815Sobrien#define WRITE_FORMAT_COMMA_x_RB(x) WRITE_FORMAT(x,",","]",",","]") 13085815Sobrien#define WRITE_FORMAT_x_RB(x) WRITE_FORMAT(x,"","]","","]") 13185815Sobrien#define WRITE_FORMAT_COMMA_x(x) WRITE_FORMAT(x,",","",",","") 13285815Sobrien#define WRITE_FORMAT_x_COMMA(x) WRITE_FORMAT(x,"",",","",",") 13385815Sobrien#define WRITE_FORMAT_x(x) WRITE_FORMAT(x,"","","","") 13485815Sobrien#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString, \ 13585815Sobrien (IS_REG (x) ? cb1"%r"ca1 : \ 13685815Sobrien usesAuxReg ? cb"%a"ca : \ 13785815Sobrien IS_SMALL (x) ? cb"%d"ca : cb"%h"ca)) 13889857Sobrien#define WRITE_FORMAT_RB() strcat (formatString, "]") 13985815Sobrien#define WRITE_COMMENT(str) (state->comm[state->commNum++] = (str)) 14089857Sobrien#define WRITE_NOP_COMMENT() if (!fieldAisReg && !flag) WRITE_COMMENT ("nop"); 14185815Sobrien 14289857Sobrien#define NEXT_WORD(x) (offset += 4, state->words[x]) 14385815Sobrien 14489857Sobrien#define add_target(x) (state->targets[state->tcnt++] = (x)) 14585815Sobrien 14685815Sobrienstatic char comment_prefix[] = "\t; "; 14785815Sobrien 14889857Sobrienstatic const char *core_reg_name PARAMS ((struct arcDisState *, int)); 14989857Sobrienstatic const char *aux_reg_name PARAMS ((struct arcDisState *, int)); 15089857Sobrienstatic const char *cond_code_name PARAMS ((struct arcDisState *, int)); 15189857Sobrienstatic const char *instruction_name 15289857Sobrien PARAMS ((struct arcDisState *, int, int, int *)); 15389857Sobrienstatic void mwerror PARAMS ((struct arcDisState *, const char *)); 15489857Sobrienstatic const char *post_address PARAMS ((struct arcDisState *, int)); 15589857Sobrienstatic void write_comments_ 15689857Sobrien PARAMS ((struct arcDisState *, int, int, long int)); 15789857Sobrienstatic void write_instr_name_ 15889857Sobrien PARAMS ((struct arcDisState *, const char *, int, int, int, int, int, int)); 15989857Sobrienstatic int dsmOneArcInst PARAMS ((bfd_vma, struct arcDisState *)); 16089857Sobrienstatic const char *_coreRegName PARAMS ((void *, int)); 16189857Sobrienstatic int decodeInstr PARAMS ((bfd_vma, disassemble_info *)); 16289857Sobrien 16385815Sobrienstatic const char * 16485815Sobriencore_reg_name (state, val) 16585815Sobrien struct arcDisState * state; 16689857Sobrien int val; 16738889Sjdp{ 16885815Sobrien if (state->coreRegName) 16985815Sobrien return (*state->coreRegName)(state->_this, val); 17085815Sobrien return 0; 17185815Sobrien} 17238889Sjdp 17385815Sobrienstatic const char * 17485815Sobrienaux_reg_name (state, val) 17585815Sobrien struct arcDisState * state; 17689857Sobrien int val; 17785815Sobrien{ 17885815Sobrien if (state->auxRegName) 17985815Sobrien return (*state->auxRegName)(state->_this, val); 18085815Sobrien return 0; 18185815Sobrien} 18285815Sobrien 18385815Sobrienstatic const char * 18485815Sobriencond_code_name (state, val) 18585815Sobrien struct arcDisState * state; 18689857Sobrien int val; 18785815Sobrien{ 18885815Sobrien if (state->condCodeName) 18985815Sobrien return (*state->condCodeName)(state->_this, val); 19085815Sobrien return 0; 19185815Sobrien} 19285815Sobrien 19385815Sobrienstatic const char * 19485815Sobrieninstruction_name (state, op1, op2, flags) 19585815Sobrien struct arcDisState * state; 19685815Sobrien int op1; 19785815Sobrien int op2; 19889857Sobrien int * flags; 19985815Sobrien{ 20085815Sobrien if (state->instName) 20185815Sobrien return (*state->instName)(state->_this, op1, op2, flags); 20285815Sobrien return 0; 20385815Sobrien} 20485815Sobrien 20585815Sobrienstatic void 20685815Sobrienmwerror (state, msg) 20785815Sobrien struct arcDisState * state; 20889857Sobrien const char * msg; 20985815Sobrien{ 21085815Sobrien if (state->err != 0) 21185815Sobrien (*state->err)(state->_this, (msg)); 21285815Sobrien} 21385815Sobrien 21485815Sobrienstatic const char * 21585815Sobrienpost_address (state, addr) 21685815Sobrien struct arcDisState * state; 21789857Sobrien int addr; 21885815Sobrien{ 21985815Sobrien static char id[3 * ARRAY_SIZE (state->addresses)]; 22085815Sobrien int j, i = state->acnt; 22185815Sobrien 22285815Sobrien if (i < ((int) ARRAY_SIZE (state->addresses))) 22338889Sjdp { 22485815Sobrien state->addresses[i] = addr; 22585815Sobrien ++state->acnt; 22685815Sobrien j = i*3; 22785815Sobrien id[j+0] = '@'; 22885815Sobrien id[j+1] = '0'+i; 22985815Sobrien id[j+2] = 0; 23089857Sobrien 23185815Sobrien return id + j; 23238889Sjdp } 23385815Sobrien return ""; 23485815Sobrien} 23538889Sjdp 23689857Sobrienstatic void my_sprintf PARAMS ((struct arcDisState *, char *, const char *, 23789857Sobrien ...)); 23889857Sobrien 23989857Sobrienstatic void 24089857Sobrienmy_sprintf VPARAMS ((struct arcDisState *state, char *buf, const char *format, 24189857Sobrien ...)) 24285815Sobrien{ 24389857Sobrien char *bp; 24485815Sobrien const char *p; 24585815Sobrien int size, leading_zero, regMap[2]; 24685815Sobrien long auxNum; 24789857Sobrien 24889857Sobrien VA_OPEN (ap, format); 24989857Sobrien VA_FIXEDARG (ap, struct arcDisState *, state); 25089857Sobrien VA_FIXEDARG (ap, char *, buf); 25189857Sobrien VA_FIXEDARG (ap, const char *, format); 25289857Sobrien 25389857Sobrien bp = buf; 25485815Sobrien *bp = 0; 25585815Sobrien p = format; 25685815Sobrien auxNum = -1; 25785815Sobrien regMap[0] = 0; 25885815Sobrien regMap[1] = 0; 25989857Sobrien 26089857Sobrien while (1) 26185815Sobrien switch (*p++) 26285815Sobrien { 26389857Sobrien case 0: 26489857Sobrien goto DOCOMM; /* (return) */ 26589857Sobrien default: 26689857Sobrien *bp++ = p[-1]; 26785815Sobrien break; 26885815Sobrien case '%': 26985815Sobrien size = 0; 27085815Sobrien leading_zero = 0; 27185815Sobrien RETRY: ; 27289857Sobrien switch (*p++) 27385815Sobrien { 27485815Sobrien case '0': 27585815Sobrien case '1': 27685815Sobrien case '2': 27785815Sobrien case '3': 27885815Sobrien case '4': 27985815Sobrien case '5': 28085815Sobrien case '6': 28185815Sobrien case '7': 28285815Sobrien case '8': 28385815Sobrien case '9': 28485815Sobrien { 28585815Sobrien /* size. */ 28685815Sobrien size = p[-1] - '0'; 28785815Sobrien if (size == 0) 28885815Sobrien leading_zero = 1; /* e.g. %08x */ 28985815Sobrien while (*p >= '0' && *p <= '9') 29085815Sobrien { 29185815Sobrien size = size * 10 + *p - '0'; 29285815Sobrien p++; 29385815Sobrien } 29485815Sobrien goto RETRY; 29585815Sobrien } 29685815Sobrien#define inc_bp() bp = bp + strlen (bp) 29785815Sobrien 29889857Sobrien case 'h': 29985815Sobrien { 30085815Sobrien unsigned u = va_arg (ap, int); 30185815Sobrien 30285815Sobrien /* Hex. We can change the format to 0x%08x in 30385815Sobrien one place, here, if we wish. 30485815Sobrien We add underscores for easy reading. */ 30589857Sobrien if (u > 65536) 30685815Sobrien sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff); 30789857Sobrien else 30885815Sobrien sprintf (bp, "0x%x", u); 30985815Sobrien inc_bp (); 31089857Sobrien } 31185815Sobrien break; 31289857Sobrien case 'X': case 'x': 31385815Sobrien { 31485815Sobrien int val = va_arg (ap, int); 31585815Sobrien 31689857Sobrien if (size != 0) 31785815Sobrien if (leading_zero) 31885815Sobrien sprintf (bp, "%0*x", size, val); 31985815Sobrien else 32085815Sobrien sprintf (bp, "%*x", size, val); 32185815Sobrien else 32285815Sobrien sprintf (bp, "%x", val); 32385815Sobrien inc_bp (); 32485815Sobrien } 32585815Sobrien break; 32689857Sobrien case 'd': 32785815Sobrien { 32885815Sobrien int val = va_arg (ap, int); 32989857Sobrien 33085815Sobrien if (size != 0) 33185815Sobrien sprintf (bp, "%*d", size, val); 33285815Sobrien else 33385815Sobrien sprintf (bp, "%d", val); 33485815Sobrien inc_bp (); 33585815Sobrien } 33685815Sobrien break; 33789857Sobrien case 'r': 33885815Sobrien { 33985815Sobrien /* Register. */ 34085815Sobrien int val = va_arg (ap, int); 34189857Sobrien 34285815Sobrien#define REG2NAME(num, name) case num: sprintf (bp, ""name); \ 34385815Sobrien regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break; 34489857Sobrien 34589857Sobrien switch (val) 34685815Sobrien { 34785815Sobrien REG2NAME (26, "gp"); 34885815Sobrien REG2NAME (27, "fp"); 34985815Sobrien REG2NAME (28, "sp"); 35085815Sobrien REG2NAME (29, "ilink1"); 35185815Sobrien REG2NAME (30, "ilink2"); 35285815Sobrien REG2NAME (31, "blink"); 35385815Sobrien REG2NAME (60, "lp_count"); 35485815Sobrien default: 35585815Sobrien { 35685815Sobrien const char * ext; 35785815Sobrien 35885815Sobrien ext = core_reg_name (state, val); 35985815Sobrien if (ext) 36085815Sobrien sprintf (bp, "%s", ext); 36185815Sobrien else 36285815Sobrien sprintf (bp,"r%d",val); 36385815Sobrien } 36485815Sobrien break; 36585815Sobrien } 36685815Sobrien inc_bp (); 36785815Sobrien } break; 36889857Sobrien 36989857Sobrien case 'a': 37085815Sobrien { 37185815Sobrien /* Aux Register. */ 37285815Sobrien int val = va_arg (ap, int); 37385815Sobrien 37485815Sobrien#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break; 37585815Sobrien 37689857Sobrien switch (val) 37785815Sobrien { 37885815Sobrien AUXREG2NAME (0x0, "status"); 37985815Sobrien AUXREG2NAME (0x1, "semaphore"); 38085815Sobrien AUXREG2NAME (0x2, "lp_start"); 38185815Sobrien AUXREG2NAME (0x3, "lp_end"); 38285815Sobrien AUXREG2NAME (0x4, "identity"); 38385815Sobrien AUXREG2NAME (0x5, "debug"); 38485815Sobrien default: 38585815Sobrien { 38685815Sobrien const char *ext; 38785815Sobrien 38885815Sobrien ext = aux_reg_name (state, val); 38985815Sobrien if (ext) 39085815Sobrien sprintf (bp, "%s", ext); 39185815Sobrien else 39285815Sobrien my_sprintf (state, bp, "%h", val); 39385815Sobrien } 39485815Sobrien break; 39585815Sobrien } 39685815Sobrien inc_bp (); 39785815Sobrien } 39885815Sobrien break; 39989857Sobrien 40089857Sobrien case 's': 40185815Sobrien { 40285815Sobrien sprintf (bp, "%s", va_arg (ap, char *)); 40385815Sobrien inc_bp (); 40485815Sobrien } 40585815Sobrien break; 40689857Sobrien 40785815Sobrien default: 40885815Sobrien fprintf (stderr, "?? format %c\n", p[-1]); 40985815Sobrien break; 41085815Sobrien } 41185815Sobrien } 41285815Sobrien 41385815Sobrien DOCOMM: *bp = 0; 41489857Sobrien VA_CLOSE (ap); 41585815Sobrien} 41685815Sobrien 41789857Sobrienstatic void 41885815Sobrienwrite_comments_(state, shimm, is_limm, limm_value) 41985815Sobrien struct arcDisState * state; 42085815Sobrien int shimm; 42185815Sobrien int is_limm; 42285815Sobrien long limm_value; 42385815Sobrien{ 42489857Sobrien if (state->commentBuffer != 0) 42538889Sjdp { 42685815Sobrien int i; 42785815Sobrien 42889857Sobrien if (is_limm) 42985815Sobrien { 43085815Sobrien const char *name = post_address (state, limm_value + shimm); 43185815Sobrien 43285815Sobrien if (*name != 0) 43385815Sobrien WRITE_COMMENT (name); 43485815Sobrien } 43589857Sobrien for (i = 0; i < state->commNum; i++) 43685815Sobrien { 43785815Sobrien if (i == 0) 43885815Sobrien strcpy (state->commentBuffer, comment_prefix); 43985815Sobrien else 44089857Sobrien strcat (state->commentBuffer, ", "); 44189857Sobrien strncat (state->commentBuffer, state->comm[i], 44289857Sobrien sizeof (state->commentBuffer)); 44385815Sobrien } 44438889Sjdp } 44585815Sobrien} 44638889Sjdp 44785815Sobrien#define write_comments2(x) write_comments_(state, x, is_limm, limm_value) 44885815Sobrien#define write_comments() write_comments2(0) 44938889Sjdp 45085815Sobrienstatic const char *condName[] = { 45185815Sobrien /* 0..15. */ 45289857Sobrien "" , "z" , "nz" , "p" , "n" , "c" , "nc" , "v" , 45385815Sobrien "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz" 45485815Sobrien}; 45538889Sjdp 45689857Sobrienstatic void 45785815Sobrienwrite_instr_name_(state, instrName, cond, condCodeIsPartOfName, flag, signExtend, addrWriteBack, directMem) 45885815Sobrien struct arcDisState * state; 45985815Sobrien const char * instrName; 46085815Sobrien int cond; 46185815Sobrien int condCodeIsPartOfName; 46285815Sobrien int flag; 46385815Sobrien int signExtend; 46485815Sobrien int addrWriteBack; 46585815Sobrien int directMem; 46685815Sobrien{ 46785815Sobrien strcpy (state->instrBuffer, instrName); 46885815Sobrien 46989857Sobrien if (cond > 0) 47038889Sjdp { 47185815Sobrien const char *cc = 0; 47238889Sjdp 47385815Sobrien if (!condCodeIsPartOfName) 47485815Sobrien strcat (state->instrBuffer, "."); 47538889Sjdp 47685815Sobrien if (cond < 16) 47785815Sobrien cc = condName[cond]; 47885815Sobrien else 47985815Sobrien cc = cond_code_name (state, cond); 48038889Sjdp 48185815Sobrien if (!cc) 48285815Sobrien cc = "???"; 48338889Sjdp 48485815Sobrien strcat (state->instrBuffer, cc); 48585815Sobrien } 48638889Sjdp 48785815Sobrien if (flag) 48885815Sobrien strcat (state->instrBuffer, ".f"); 48938889Sjdp 49089857Sobrien switch (state->nullifyMode) 49185815Sobrien { 49285815Sobrien case BR_exec_always: 49385815Sobrien strcat (state->instrBuffer, ".d"); 49485815Sobrien break; 49585815Sobrien case BR_exec_when_jump: 49685815Sobrien strcat (state->instrBuffer, ".jd"); 49785815Sobrien break; 49885815Sobrien } 49938889Sjdp 50085815Sobrien if (signExtend) 50185815Sobrien strcat (state->instrBuffer, ".x"); 50238889Sjdp 50385815Sobrien if (addrWriteBack) 50485815Sobrien strcat (state->instrBuffer, ".a"); 50538889Sjdp 50685815Sobrien if (directMem) 50785815Sobrien strcat (state->instrBuffer, ".di"); 50885815Sobrien} 50985815Sobrien 51085815Sobrien#define write_instr_name() \ 51185815Sobrien do \ 51285815Sobrien { \ 51385815Sobrien write_instr_name_(state, instrName,cond, condCodeIsPartOfName, \ 51485815Sobrien flag, signExtend, addrWriteBack, directMem); \ 51585815Sobrien formatString[0] = '\0'; \ 51685815Sobrien } \ 51785815Sobrien while (0) 51885815Sobrien 51989857Sobrienenum { 52089857Sobrien op_LD0 = 0, op_LD1 = 1, op_ST = 2, op_3 = 3, 52185815Sobrien op_BC = 4, op_BLC = 5, op_LPC = 6, op_JC = 7, 52289857Sobrien op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11, 52385815Sobrien op_AND = 12, op_OR = 13, op_BIC = 14, op_XOR = 15 52485815Sobrien}; 52585815Sobrien 52685815Sobrienextern disassemble_info tm_print_insn_info; 52785815Sobrien 52889857Sobrienstatic int 52985815SobriendsmOneArcInst (addr, state) 53085815Sobrien bfd_vma addr; 53185815Sobrien struct arcDisState * state; 53285815Sobrien{ 53385815Sobrien int condCodeIsPartOfName = 0; 53485815Sobrien int decodingClass; 53585815Sobrien const char * instrName; 53685815Sobrien int repeatsOp = 0; 53785815Sobrien int fieldAisReg = 1; 53885815Sobrien int fieldBisReg = 1; 53985815Sobrien int fieldCisReg = 1; 54085815Sobrien int fieldA; 54185815Sobrien int fieldB; 54285815Sobrien int fieldC = 0; 54385815Sobrien int flag = 0; 54485815Sobrien int cond = 0; 54585815Sobrien int is_shimm = 0; 54685815Sobrien int is_limm = 0; 54785815Sobrien long limm_value = 0; 54885815Sobrien int signExtend = 0; 54985815Sobrien int addrWriteBack = 0; 55085815Sobrien int directMem = 0; 55185815Sobrien int is_linked = 0; 55285815Sobrien int offset = 0; 55385815Sobrien int usesAuxReg = 0; 55485815Sobrien int flags; 55585815Sobrien int ignoreFirstOpd; 55685815Sobrien char formatString[60]; 55789857Sobrien 55885815Sobrien state->instructionLen = 4; 55985815Sobrien state->nullifyMode = BR_exec_when_no_jump; 56085815Sobrien state->opWidth = 12; 56185815Sobrien state->isBranch = 0; 56289857Sobrien 56385815Sobrien state->_mem_load = 0; 56485815Sobrien state->_ea_present = 0; 56585815Sobrien state->_load_len = 0; 56685815Sobrien state->ea_reg1 = no_reg; 56785815Sobrien state->ea_reg2 = no_reg; 56885815Sobrien state->_offset = 0; 56989857Sobrien 57085815Sobrien if (! NEXT_WORD (0)) 57185815Sobrien return 0; 57289857Sobrien 57385815Sobrien state->_opcode = OPCODE (state->words[0]); 57485815Sobrien instrName = 0; 57585815Sobrien decodingClass = 0; /* default! */ 57685815Sobrien repeatsOp = 0; 57785815Sobrien condCodeIsPartOfName=0; 57885815Sobrien state->commNum = 0; 57985815Sobrien state->tcnt = 0; 58085815Sobrien state->acnt = 0; 58185815Sobrien state->flow = noflow; 58285815Sobrien ignoreFirstOpd = 0; 58385815Sobrien 58485815Sobrien if (state->commentBuffer) 58585815Sobrien state->commentBuffer[0] = '\0'; 58685815Sobrien 58789857Sobrien switch (state->_opcode) 58885815Sobrien { 58989857Sobrien case op_LD0: 59089857Sobrien switch (BITS (state->words[0],1,2)) 59138889Sjdp { 59285815Sobrien case 0: 59385815Sobrien instrName = "ld"; 59485815Sobrien state->_load_len = 4; 59585815Sobrien break; 59685815Sobrien case 1: 59785815Sobrien instrName = "ldb"; 59885815Sobrien state->_load_len = 1; 59985815Sobrien break; 60085815Sobrien case 2: 60185815Sobrien instrName = "ldw"; 60285815Sobrien state->_load_len = 2; 60385815Sobrien break; 60485815Sobrien default: 60589857Sobrien instrName = "??? (0[3])"; 60685815Sobrien state->flow = invalid_instr; 60785815Sobrien break; 60885815Sobrien } 60989857Sobrien decodingClass = 5; 61085815Sobrien break; 61189857Sobrien 61289857Sobrien case op_LD1: 61389857Sobrien if (BIT (state->words[0],13)) 61485815Sobrien { 61589857Sobrien instrName = "lr"; 61685815Sobrien decodingClass = 10; 61785815Sobrien } 61889857Sobrien else 61985815Sobrien { 62089857Sobrien switch (BITS (state->words[0],10,11)) 62138889Sjdp { 62285815Sobrien case 0: 62385815Sobrien instrName = "ld"; 62485815Sobrien state->_load_len = 4; 62585815Sobrien break; 62685815Sobrien case 1: 62785815Sobrien instrName = "ldb"; 62885815Sobrien state->_load_len = 1; 62985815Sobrien break; 63085815Sobrien case 2: 63185815Sobrien instrName = "ldw"; 63285815Sobrien state->_load_len = 2; 63385815Sobrien break; 63485815Sobrien default: 63589857Sobrien instrName = "??? (1[3])"; 63685815Sobrien state->flow = invalid_instr; 63785815Sobrien break; 63838889Sjdp } 63985815Sobrien decodingClass = 6; 64038889Sjdp } 64185815Sobrien break; 64289857Sobrien 64385815Sobrien case op_ST: 64489857Sobrien if (BIT (state->words[0],25)) 64538889Sjdp { 64685815Sobrien instrName = "sr"; 64785815Sobrien decodingClass = 8; 64885815Sobrien } 64989857Sobrien else 65085815Sobrien { 65189857Sobrien switch (BITS (state->words[0],22,23)) 65238889Sjdp { 65385815Sobrien case 0: 65485815Sobrien instrName = "st"; 65585815Sobrien break; 65685815Sobrien case 1: 65785815Sobrien instrName = "stb"; 65885815Sobrien break; 65985815Sobrien case 2: 66085815Sobrien instrName = "stw"; 66185815Sobrien break; 66285815Sobrien default: 66389857Sobrien instrName = "??? (2[3])"; 66485815Sobrien state->flow = invalid_instr; 66585815Sobrien break; 66638889Sjdp } 66785815Sobrien decodingClass = 7; 66885815Sobrien } 66985815Sobrien break; 67089857Sobrien 67185815Sobrien case op_3: 67285815Sobrien decodingClass = 1; /* default for opcode 3... */ 67389857Sobrien switch (FIELDC (state->words[0])) 67485815Sobrien { 67585815Sobrien case 0: 67689857Sobrien instrName = "flag"; 67785815Sobrien decodingClass = 2; 67885815Sobrien break; 67985815Sobrien case 1: 68085815Sobrien instrName = "asr"; 68185815Sobrien break; 68285815Sobrien case 2: 68385815Sobrien instrName = "lsr"; 68485815Sobrien break; 68585815Sobrien case 3: 68685815Sobrien instrName = "ror"; 68785815Sobrien break; 68885815Sobrien case 4: 68985815Sobrien instrName = "rrc"; 69085815Sobrien break; 69185815Sobrien case 5: 69285815Sobrien instrName = "sexb"; 69385815Sobrien break; 69485815Sobrien case 6: 69585815Sobrien instrName = "sexw"; 69685815Sobrien break; 69785815Sobrien case 7: 69885815Sobrien instrName = "extb"; 69985815Sobrien break; 70085815Sobrien case 8: 70185815Sobrien instrName = "extw"; 70285815Sobrien break; 70389857Sobrien case 0x3f: 70485815Sobrien { 70585815Sobrien decodingClass = 9; 70689857Sobrien switch( FIELDD (state->words[0]) ) 70785815Sobrien { 70885815Sobrien case 0: 70985815Sobrien instrName = "brk"; 71085815Sobrien break; 71185815Sobrien case 1: 71285815Sobrien instrName = "sleep"; 71385815Sobrien break; 71485815Sobrien case 2: 71585815Sobrien instrName = "swi"; 71685815Sobrien break; 71785815Sobrien default: 71885815Sobrien instrName = "???"; 71985815Sobrien state->flow=invalid_instr; 72085815Sobrien break; 72185815Sobrien } 72285815Sobrien } 72385815Sobrien break; 72489857Sobrien 72585815Sobrien /* ARC Extension Library Instructions 72685815Sobrien NOTE: We assume that extension codes are these instrs. */ 72785815Sobrien default: 72885815Sobrien instrName = instruction_name (state, 72985815Sobrien state->_opcode, 73085815Sobrien FIELDC (state->words[0]), 73189857Sobrien &flags); 73285815Sobrien if (!instrName) 73338889Sjdp { 73485815Sobrien instrName = "???"; 73585815Sobrien state->flow = invalid_instr; 73638889Sjdp } 73785815Sobrien if (flags & IGNORE_FIRST_OPD) 73885815Sobrien ignoreFirstOpd = 1; 73985815Sobrien break; 74085815Sobrien } 74185815Sobrien break; 74238889Sjdp 74385815Sobrien case op_BC: 74489857Sobrien instrName = "b"; 74585815Sobrien case op_BLC: 74685815Sobrien if (!instrName) 74789857Sobrien instrName = "bl"; 74885815Sobrien case op_LPC: 74985815Sobrien if (!instrName) 75089857Sobrien instrName = "lp"; 75185815Sobrien case op_JC: 75285815Sobrien if (!instrName) 75385815Sobrien { 75489857Sobrien if (BITS (state->words[0],9,9)) 75538889Sjdp { 75689857Sobrien instrName = "jl"; 75785815Sobrien is_linked = 1; 75838889Sjdp } 75989857Sobrien else 76038889Sjdp { 76189857Sobrien instrName = "j"; 76285815Sobrien is_linked = 0; 76338889Sjdp } 76485815Sobrien } 76585815Sobrien condCodeIsPartOfName = 1; 76685815Sobrien decodingClass = ((state->_opcode == op_JC) ? 4 : 3); 76785815Sobrien state->isBranch = 1; 76885815Sobrien break; 76989857Sobrien 77085815Sobrien case op_ADD: 77185815Sobrien case op_ADC: 77285815Sobrien case op_AND: 77385815Sobrien repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0])); 77485815Sobrien decodingClass = 0; 77538889Sjdp 77689857Sobrien switch (state->_opcode) 77785815Sobrien { 77885815Sobrien case op_ADD: 77985815Sobrien instrName = (repeatsOp ? "asl" : "add"); 78085815Sobrien break; 78185815Sobrien case op_ADC: 78285815Sobrien instrName = (repeatsOp ? "rlc" : "adc"); 78385815Sobrien break; 78485815Sobrien case op_AND: 78585815Sobrien instrName = (repeatsOp ? "mov" : "and"); 78685815Sobrien break; 78785815Sobrien } 78885815Sobrien break; 78989857Sobrien 79085815Sobrien case op_SUB: instrName = "sub"; 79185815Sobrien break; 79285815Sobrien case op_SBC: instrName = "sbc"; 79385815Sobrien break; 79485815Sobrien case op_OR: instrName = "or"; 79585815Sobrien break; 79685815Sobrien case op_BIC: instrName = "bic"; 79785815Sobrien break; 79885815Sobrien 79985815Sobrien case op_XOR: 80085815Sobrien if (state->words[0] == 0x7fffffff) 80185815Sobrien { 80285815Sobrien /* nop encoded as xor -1, -1, -1 */ 80385815Sobrien instrName = "nop"; 80485815Sobrien decodingClass = 9; 80585815Sobrien } 80689857Sobrien else 80785815Sobrien instrName = "xor"; 80885815Sobrien break; 80989857Sobrien 81085815Sobrien default: 81185815Sobrien instrName = instruction_name (state,state->_opcode,0,&flags); 81285815Sobrien /* if (instrName) printf("FLAGS=0x%x\n", flags); */ 81385815Sobrien if (!instrName) 81485815Sobrien { 81585815Sobrien instrName = "???"; 81685815Sobrien state->flow=invalid_instr; 81785815Sobrien } 81885815Sobrien if (flags & IGNORE_FIRST_OPD) 81985815Sobrien ignoreFirstOpd = 1; 82085815Sobrien break; 82185815Sobrien } 82289857Sobrien 82385815Sobrien fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now. */ 82485815Sobrien flag = cond = is_shimm = is_limm = 0; 82585815Sobrien state->nullifyMode = BR_exec_when_no_jump; /* 0 */ 82685815Sobrien signExtend = addrWriteBack = directMem = 0; 82785815Sobrien usesAuxReg = 0; 82889857Sobrien 82989857Sobrien switch (decodingClass) 83085815Sobrien { 83185815Sobrien case 0: 83285815Sobrien CHECK_FIELD_A (); 83385815Sobrien CHECK_FIELD_B (); 83485815Sobrien if (!repeatsOp) 83585815Sobrien CHECK_FIELD_C (); 83685815Sobrien CHECK_FLAG_COND_NULLIFY (); 83789857Sobrien 83885815Sobrien write_instr_name (); 83989857Sobrien if (!ignoreFirstOpd) 84085815Sobrien { 84185815Sobrien WRITE_FORMAT_x (A); 84285815Sobrien WRITE_FORMAT_COMMA_x (B); 84385815Sobrien if (!repeatsOp) 84485815Sobrien WRITE_FORMAT_COMMA_x (C); 84585815Sobrien WRITE_NOP_COMMENT (); 84689857Sobrien my_sprintf (state, state->operandBuffer, formatString, 84789857Sobrien fieldA, fieldB, fieldC); 84885815Sobrien } 84989857Sobrien else 85085815Sobrien { 85185815Sobrien WRITE_FORMAT_x (B); 85285815Sobrien if (!repeatsOp) 85385815Sobrien WRITE_FORMAT_COMMA_x (C); 85489857Sobrien my_sprintf (state, state->operandBuffer, formatString, 85589857Sobrien fieldB, fieldC); 85685815Sobrien } 85785815Sobrien write_comments (); 85885815Sobrien break; 85989857Sobrien 86085815Sobrien case 1: 86185815Sobrien CHECK_FIELD_A (); 86285815Sobrien CHECK_FIELD_B (); 86385815Sobrien CHECK_FLAG_COND_NULLIFY (); 86489857Sobrien 86585815Sobrien write_instr_name (); 86689857Sobrien if (!ignoreFirstOpd) 86785815Sobrien { 86885815Sobrien WRITE_FORMAT_x (A); 86985815Sobrien WRITE_FORMAT_COMMA_x (B); 87085815Sobrien WRITE_NOP_COMMENT (); 87189857Sobrien my_sprintf (state, state->operandBuffer, formatString, 87289857Sobrien fieldA, fieldB); 87385815Sobrien } 87489857Sobrien else 87585815Sobrien { 87685815Sobrien WRITE_FORMAT_x (B); 87789857Sobrien my_sprintf (state, state->operandBuffer, formatString, fieldB); 87885815Sobrien } 87985815Sobrien write_comments (); 88085815Sobrien break; 88189857Sobrien 88285815Sobrien case 2: 88385815Sobrien CHECK_FIELD_B (); 88485815Sobrien CHECK_FLAG_COND_NULLIFY (); 88585815Sobrien flag = 0; /* this is the FLAG instruction -- it's redundant */ 88689857Sobrien 88785815Sobrien write_instr_name (); 88885815Sobrien WRITE_FORMAT_x (B); 88985815Sobrien my_sprintf (state, state->operandBuffer, formatString, fieldB); 89085815Sobrien write_comments (); 89185815Sobrien break; 89289857Sobrien 89385815Sobrien case 3: 89485815Sobrien fieldA = BITS (state->words[0],7,26) << 2; 89585815Sobrien fieldA = (fieldA << 10) >> 10; /* make it signed */ 89685815Sobrien fieldA += addr + 4; 89785815Sobrien CHECK_FLAG_COND_NULLIFY (); 89885815Sobrien flag = 0; 89989857Sobrien 90085815Sobrien write_instr_name (); 90185815Sobrien /* This address could be a label we know. Convert it. */ 90289857Sobrien if (state->_opcode != op_LPC /* LP */) 90385815Sobrien { 90489857Sobrien add_target (fieldA); /* For debugger. */ 90589857Sobrien state->flow = state->_opcode == op_BLC /* BL */ 90689857Sobrien ? direct_call 90789857Sobrien : direct_jump; 90889857Sobrien /* indirect calls are achieved by "lr blink,[status]; 90989857Sobrien lr dest<- func addr; j [dest]" */ 91089857Sobrien } 91189857Sobrien 91285815Sobrien strcat (formatString, "%s"); /* address/label name */ 91389857Sobrien my_sprintf (state, state->operandBuffer, formatString, 91489857Sobrien post_address (state, fieldA)); 91585815Sobrien write_comments (); 91685815Sobrien break; 91789857Sobrien 91885815Sobrien case 4: 91985815Sobrien /* For op_JC -- jump to address specified. 92085815Sobrien Also covers jump and link--bit 9 of the instr. word 92185815Sobrien selects whether linked, thus "is_linked" is set above. */ 92285815Sobrien fieldA = 0; 92385815Sobrien CHECK_FIELD_B (); 92485815Sobrien CHECK_FLAG_COND_NULLIFY (); 92589857Sobrien 92689857Sobrien if (!fieldBisReg) 92785815Sobrien { 92885815Sobrien fieldAisReg = 0; 92985815Sobrien fieldA = (fieldB >> 25) & 0x7F; /* flags */ 93085815Sobrien fieldB = (fieldB & 0xFFFFFF) << 2; 93185815Sobrien state->flow = is_linked ? direct_call : direct_jump; 93285815Sobrien add_target (fieldB); 93385815Sobrien /* screwy JLcc requires .jd mode to execute correctly 93485815Sobrien * but we pretend it is .nd (no delay slot). */ 93585815Sobrien if (is_linked && state->nullifyMode == BR_exec_when_jump) 93685815Sobrien state->nullifyMode = BR_exec_when_no_jump; 93785815Sobrien } 93889857Sobrien else 93985815Sobrien { 94085815Sobrien state->flow = is_linked ? indirect_call : indirect_jump; 94185815Sobrien /* We should also treat this as indirect call if NOT linked 94285815Sobrien * but the preceding instruction was a "lr blink,[status]" 94385815Sobrien * and we have a delay slot with "add blink,blink,2". 94485815Sobrien * For now we can't detect such. */ 94585815Sobrien state->register_for_indirect_jump = fieldB; 94685815Sobrien } 94789857Sobrien 94885815Sobrien write_instr_name (); 94989857Sobrien strcat (formatString, 95085815Sobrien IS_REG (B) ? "[%r]" : "%s"); /* address/label name */ 95189857Sobrien if (fieldA != 0) 95285815Sobrien { 95385815Sobrien fieldAisReg = 0; 95485815Sobrien WRITE_FORMAT_COMMA_x (A); 95585815Sobrien } 95685815Sobrien if (IS_REG (B)) 95785815Sobrien my_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA); 95885815Sobrien else 95989857Sobrien my_sprintf (state, state->operandBuffer, formatString, 96085815Sobrien post_address (state, fieldB), fieldA); 96185815Sobrien write_comments (); 96285815Sobrien break; 96389857Sobrien 96485815Sobrien case 5: 96585815Sobrien /* LD instruction. 96685815Sobrien B and C can be regs, or one (both?) can be limm. */ 96785815Sobrien CHECK_FIELD_A (); 96885815Sobrien CHECK_FIELD_B (); 96985815Sobrien CHECK_FIELD_C (); 97085815Sobrien if (dbg) 97185815Sobrien printf ("5:b reg %d %d c reg %d %d \n", 97285815Sobrien fieldBisReg,fieldB,fieldCisReg,fieldC); 97385815Sobrien state->_offset = 0; 97485815Sobrien state->_ea_present = 1; 97585815Sobrien if (fieldBisReg) 97685815Sobrien state->ea_reg1 = fieldB; 97785815Sobrien else 97885815Sobrien state->_offset += fieldB; 97985815Sobrien if (fieldCisReg) 98085815Sobrien state->ea_reg2 = fieldC; 98185815Sobrien else 98285815Sobrien state->_offset += fieldC; 98385815Sobrien state->_mem_load = 1; 98489857Sobrien 98585815Sobrien directMem = BIT (state->words[0],5); 98685815Sobrien addrWriteBack = BIT (state->words[0],3); 98785815Sobrien signExtend = BIT (state->words[0],0); 98889857Sobrien 98985815Sobrien write_instr_name (); 99085815Sobrien WRITE_FORMAT_x_COMMA_LB(A); 99185815Sobrien if (fieldBisReg || fieldB != 0) 99285815Sobrien WRITE_FORMAT_x_COMMA (B); 99385815Sobrien else 99485815Sobrien fieldB = fieldC; 99589857Sobrien 99685815Sobrien WRITE_FORMAT_x_RB (C); 99789857Sobrien my_sprintf (state, state->operandBuffer, formatString, 99889857Sobrien fieldA, fieldB, fieldC); 99985815Sobrien write_comments (); 100085815Sobrien break; 100189857Sobrien 100285815Sobrien case 6: 100385815Sobrien /* LD instruction. */ 100485815Sobrien CHECK_FIELD_B (); 100585815Sobrien CHECK_FIELD_A (); 100685815Sobrien fieldC = FIELDD (state->words[0]); 100789857Sobrien 100885815Sobrien if (dbg) 100985815Sobrien printf ("6:b reg %d %d c 0x%x \n", 101085815Sobrien fieldBisReg, fieldB, fieldC); 101185815Sobrien state->_ea_present = 1; 101285815Sobrien state->_offset = fieldC; 101385815Sobrien state->_mem_load = 1; 101485815Sobrien if (fieldBisReg) 101585815Sobrien state->ea_reg1 = fieldB; 101685815Sobrien /* field B is either a shimm (same as fieldC) or limm (different!) 101785815Sobrien Say ea is not present, so only one of us will do the name lookup. */ 101885815Sobrien else 101985815Sobrien state->_offset += fieldB, state->_ea_present = 0; 102089857Sobrien 102185815Sobrien directMem = BIT (state->words[0],14); 102285815Sobrien addrWriteBack = BIT (state->words[0],12); 102385815Sobrien signExtend = BIT (state->words[0],9); 102489857Sobrien 102585815Sobrien write_instr_name (); 102685815Sobrien WRITE_FORMAT_x_COMMA_LB (A); 102789857Sobrien if (!fieldBisReg) 102885815Sobrien { 102985815Sobrien fieldB = state->_offset; 103085815Sobrien WRITE_FORMAT_x_RB (B); 103185815Sobrien } 103289857Sobrien else 103385815Sobrien { 103485815Sobrien WRITE_FORMAT_x (B); 103589857Sobrien if (fieldC != 0 && !BIT (state->words[0],13)) 103638889Sjdp { 103785815Sobrien fieldCisReg = 0; 103885815Sobrien WRITE_FORMAT_COMMA_x_RB (C); 103938889Sjdp } 104038889Sjdp else 104185815Sobrien WRITE_FORMAT_RB (); 104238889Sjdp } 104389857Sobrien my_sprintf (state, state->operandBuffer, formatString, 104489857Sobrien fieldA, fieldB, fieldC); 104585815Sobrien write_comments (); 104685815Sobrien break; 104789857Sobrien 104885815Sobrien case 7: 104985815Sobrien /* ST instruction. */ 105085815Sobrien CHECK_FIELD_B(); 105185815Sobrien CHECK_FIELD_C(); 105285815Sobrien fieldA = FIELDD(state->words[0]); /* shimm */ 105389857Sobrien 105485815Sobrien /* [B,A offset] */ 105585815Sobrien if (dbg) printf("7:b reg %d %x off %x\n", 105689857Sobrien fieldBisReg,fieldB,fieldA); 105785815Sobrien state->_ea_present = 1; 105885815Sobrien state->_offset = fieldA; 105985815Sobrien if (fieldBisReg) 106085815Sobrien state->ea_reg1 = fieldB; 106189857Sobrien /* field B is either a shimm (same as fieldA) or limm (different!) 106285815Sobrien Say ea is not present, so only one of us will do the name lookup. 106385815Sobrien (for is_limm we do the name translation here). */ 106489857Sobrien else 106585815Sobrien state->_offset += fieldB, state->_ea_present = 0; 106689857Sobrien 106785815Sobrien directMem = BIT(state->words[0],26); 106885815Sobrien addrWriteBack = BIT(state->words[0],24); 106989857Sobrien 107085815Sobrien write_instr_name(); 107185815Sobrien WRITE_FORMAT_x_COMMA_LB(C); 107289857Sobrien 107389857Sobrien if (!fieldBisReg) 107485815Sobrien { 107585815Sobrien fieldB = state->_offset; 107685815Sobrien WRITE_FORMAT_x_RB(B); 107785815Sobrien } 107889857Sobrien else 107985815Sobrien { 108085815Sobrien WRITE_FORMAT_x(B); 108189857Sobrien if (fieldBisReg && fieldA != 0) 108285815Sobrien { 108385815Sobrien fieldAisReg = 0; 108485815Sobrien WRITE_FORMAT_COMMA_x_RB(A); 108585815Sobrien } 108685815Sobrien else 108785815Sobrien WRITE_FORMAT_RB(); 108885815Sobrien } 108989857Sobrien my_sprintf (state, state->operandBuffer, formatString, 109089857Sobrien fieldC, fieldB, fieldA); 109185815Sobrien write_comments2(fieldA); 109285815Sobrien break; 109385815Sobrien case 8: 109485815Sobrien /* SR instruction */ 109585815Sobrien CHECK_FIELD_B(); 109685815Sobrien CHECK_FIELD_C(); 109789857Sobrien 109885815Sobrien write_instr_name(); 109985815Sobrien WRITE_FORMAT_x_COMMA_LB(C); 110085815Sobrien /* Try to print B as an aux reg if it is not a core reg. */ 110185815Sobrien usesAuxReg = 1; 110285815Sobrien WRITE_FORMAT_x(B); 110385815Sobrien WRITE_FORMAT_RB(); 110485815Sobrien my_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB); 110585815Sobrien write_comments(); 110685815Sobrien break; 110789857Sobrien 110885815Sobrien case 9: 110985815Sobrien write_instr_name(); 111085815Sobrien state->operandBuffer[0] = '\0'; 111185815Sobrien break; 111289857Sobrien 111385815Sobrien case 10: 111485815Sobrien /* LR instruction */ 111585815Sobrien CHECK_FIELD_A(); 111685815Sobrien CHECK_FIELD_B(); 111789857Sobrien 111885815Sobrien write_instr_name(); 111985815Sobrien WRITE_FORMAT_x_COMMA_LB(A); 112085815Sobrien /* Try to print B as an aux reg if it is not a core reg. */ 112185815Sobrien usesAuxReg = 1; 112285815Sobrien WRITE_FORMAT_x(B); 112385815Sobrien WRITE_FORMAT_RB(); 112485815Sobrien my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB); 112585815Sobrien write_comments(); 112685815Sobrien break; 112789857Sobrien 112885815Sobrien case 11: 112985815Sobrien CHECK_COND(); 113085815Sobrien write_instr_name(); 113185815Sobrien state->operandBuffer[0] = '\0'; 113285815Sobrien break; 113389857Sobrien 113485815Sobrien default: 113585815Sobrien mwerror (state, "Bad decoding class in ARC disassembler"); 113685815Sobrien break; 113738889Sjdp } 113889857Sobrien 113985815Sobrien state->_cond = cond; 114085815Sobrien return state->instructionLen = offset; 114185815Sobrien} 114238889Sjdp 114385815Sobrien 114485815Sobrien/* Returns the name the user specified core extension register. */ 114585815Sobrienstatic const char * 114685815Sobrien_coreRegName(arg, regval) 114785815Sobrien void * arg ATTRIBUTE_UNUSED; 114885815Sobrien int regval; 114985815Sobrien{ 115085815Sobrien return arcExtMap_coreRegName (regval); 115138889Sjdp} 115238889Sjdp 115385815Sobrien/* Returns the name the user specified AUX extension register. */ 115485815Sobrienstatic const char * 115585815Sobrien_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval) 115685815Sobrien{ 115789857Sobrien return arcExtMap_auxRegName(regval); 115885815Sobrien} 115938889Sjdp 116085815Sobrien 116185815Sobrien/* Returns the name the user specified condition code name. */ 116285815Sobrienstatic const char * 116385815Sobrien_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval) 116438889Sjdp{ 116589857Sobrien return arcExtMap_condCodeName(regval); 116638889Sjdp} 116738889Sjdp 116885815Sobrien/* Returns the name the user specified extension instruction. */ 116985815Sobrienstatic const char * 117085815Sobrien_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags) 117138889Sjdp{ 117289857Sobrien return arcExtMap_instName(majop, minop, flags); 117338889Sjdp} 117438889Sjdp 117585815Sobrien/* Decode an instruction returning the size of the instruction 117685815Sobrien in bytes or zero if unrecognized. */ 117738889Sjdpstatic int 117885815SobriendecodeInstr (address, info) 117985815Sobrien bfd_vma address; /* Address of this instruction. */ 118085815Sobrien disassemble_info * info; 118138889Sjdp{ 118285815Sobrien int status; 118385815Sobrien bfd_byte buffer[4]; 118485815Sobrien struct arcDisState s; /* ARC Disassembler state */ 118585815Sobrien void *stream = info->stream; /* output stream */ 118689857Sobrien fprintf_ftype func = info->fprintf_func; 118785815Sobrien int bytes; 118889857Sobrien 118985815Sobrien memset (&s, 0, sizeof(struct arcDisState)); 119089857Sobrien 119185815Sobrien /* read first instruction */ 119285815Sobrien status = (*info->read_memory_func) (address, buffer, 4, info); 119385815Sobrien if (status != 0) 119485815Sobrien { 119585815Sobrien (*info->memory_error_func) (status, address, info); 119685815Sobrien return 0; 119785815Sobrien } 119885815Sobrien if (info->endian == BFD_ENDIAN_LITTLE) 119985815Sobrien s.words[0] = bfd_getl32(buffer); 120085815Sobrien else 120185815Sobrien s.words[0] = bfd_getb32(buffer); 120285815Sobrien /* always read second word in case of limm */ 120385815Sobrien 120485815Sobrien /* we ignore the result since last insn may not have a limm */ 120585815Sobrien status = (*info->read_memory_func) (address + 4, buffer, 4, info); 120685815Sobrien if (info->endian == BFD_ENDIAN_LITTLE) 120785815Sobrien s.words[1] = bfd_getl32(buffer); 120885815Sobrien else 120985815Sobrien s.words[1] = bfd_getb32(buffer); 121085815Sobrien 121185815Sobrien s._this = &s; 121285815Sobrien s.coreRegName = _coreRegName; 121385815Sobrien s.auxRegName = _auxRegName; 121485815Sobrien s.condCodeName = _condCodeName; 121585815Sobrien s.instName = _instName; 121685815Sobrien 121785815Sobrien /* disassemble */ 121885815Sobrien bytes = dsmOneArcInst(address, (void *)&s); 121985815Sobrien 122085815Sobrien /* display the disassembly instruction */ 122185815Sobrien (*func) (stream, "%08x ", s.words[0]); 122285815Sobrien (*func) (stream, " "); 122389857Sobrien 122485815Sobrien (*func) (stream, "%-10s ", s.instrBuffer); 122589857Sobrien 122685815Sobrien if (__TRANSLATION_REQUIRED(s)) 122785815Sobrien { 122885815Sobrien bfd_vma addr = s.addresses[s.operandBuffer[1] - '0']; 122985815Sobrien (*info->print_address_func) ((bfd_vma) addr, info); 123085815Sobrien (*func) (stream, "\n"); 123185815Sobrien } 123285815Sobrien else 123385815Sobrien (*func) (stream, "%s",s.operandBuffer); 123485815Sobrien return s.instructionLen; 123538889Sjdp} 123685815Sobrien 123785815Sobrien/* Return the print_insn function to use. 123885815Sobrien Side effect: load (possibly empty) extension section */ 123985815Sobrien 124085815Sobriendisassembler_ftype 124185815Sobrienarc_get_disassembler (void *ptr) 124285815Sobrien{ 124385815Sobrien if (ptr) 124485815Sobrien build_ARC_extmap (ptr); 124585815Sobrien return decodeInstr; 124685815Sobrien} 1247