diff --git a/Externals/Bochs_disasm/Bochs_disasm.vcxproj b/Externals/Bochs_disasm/Bochs_disasm.vcxproj index 4bd9dd4a43..917b83248d 100644 --- a/Externals/Bochs_disasm/Bochs_disasm.vcxproj +++ b/Externals/Bochs_disasm/Bochs_disasm.vcxproj @@ -1,4 +1,4 @@ - + @@ -48,12 +48,10 @@ - - diff --git a/Externals/Bochs_disasm/CMakeLists.txt b/Externals/Bochs_disasm/CMakeLists.txt index 93a73f9392..a58e50e928 100644 --- a/Externals/Bochs_disasm/CMakeLists.txt +++ b/Externals/Bochs_disasm/CMakeLists.txt @@ -1,11 +1,10 @@ -set(SRCS dis_decode.cpp - dis_groups.cpp - resolve.cpp - syntax.cpp - PowerPCDisasm.cpp) +set(SRCS dis_decode.cpp + dis_groups.cpp + resolve.cpp + syntax.cpp) if(WIN32) - set(SRCS ${SRCS} stdafx.cpp) + set(SRCS ${SRCS} stdafx.cpp) endif(WIN32) add_library(bdisasm STATIC ${SRCS}) diff --git a/Externals/Bochs_disasm/PowerPCDisasm.cpp b/Externals/Bochs_disasm/PowerPCDisasm.cpp deleted file mode 100644 index f6de85d845..0000000000 --- a/Externals/Bochs_disasm/PowerPCDisasm.cpp +++ /dev/null @@ -1,2285 +0,0 @@ -/* $VER: ppc_disasm.c V1.1 (19.02.2000) -* -* Disassembler module for the PowerPC microprocessor family -* Copyright (c) 1998-2000 Frank Wille -* -* ppc_disasm.c is freeware and may be freely redistributed as long as -* no modifications are made and nothing is charged for it. -* Non-commercial usage is allowed without any restrictions. -* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE -* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR. -* -* -* v1.2 (31.07.2003) org -* modified for IBM PowerPC Gekko. -* v1.1 (19.02.2000) phx -* fabs wasn't recognized. -* v1.0 (30.01.2000) phx -* stfsx, stfdx, lfsx, lfdx, stfsux, stfdux, lfsux, lfdux, etc. -* printed "rd,ra,rb" as operands instead "fd,ra,rb". -* v0.4 (01.06.1999) phx -* 'stwm' shoud have been 'stmw'. -* v0.3 (17.11.1998) phx -* The OE-types (e.g. addo, subfeo, etc.) didn't work for all -* instructions. -* AA-form branches have an absolute destination. -* addze and subfze must not have a third operand. -* sc was not recognized. -* v0.2 (29.05.1998) phx -* Sign error. SUBI got negative immediate values. -* v0.1 (23.05.1998) phx -* First version, which implements all PowerPC instructions. -* v0.0 (09.05.1998) phx -* File created. -*/ -#include -#include -#include -#include - -#include "PowerPCDisasm.h" - -namespace PPCDisasm -{ - -/* version/revision */ -#define PPCDISASM_VER 1 -#define PPCDISASM_REV 1 - - -/* typedefs */ -typedef unsigned int ppc_word; - -#undef BIGENDIAN -#undef LITTTLEENDIAN -/* endianess */ -#define LITTLEENDIAN 0 - - -/* general defines */ -#define PPCIDXMASK 0xfc000000 -#define PPCIDX2MASK 0x000007fe -#define PPCDMASK 0x03e00000 -#define PPCAMASK 0x001f0000 -#define PPCBMASK 0x0000f800 -#define PPCCMASK 0x000007c0 -#define PPCMMASK 0x0000003e -#define PPCCRDMASK 0x03800000 -#define PPCCRAMASK 0x001c0000 -#define PPCLMASK 0x00600000 -#define PPCOE 0x00000400 - -#define PPCIDXSH 26 -#define PPCDSH 21 -#define PPCASH 16 -#define PPCBSH 11 -#define PPCCSH 6 -#define PPCMSH 1 -#define PPCCRDSH 23 -#define PPCCRASH 18 -#define PPCLSH 21 -#define PPCIDX2SH 1 - -#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH) -#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH) -#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH) -#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH) -#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH) -#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH) -#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH) -#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH) -#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH) -#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH) - - - /* Disassembler structure, the interface to the application */ - - struct DisasmPara_PPC { - ppc_word *instr; /* pointer to instruction to disassemble */ - ppc_word *iaddr; /* instr.addr., usually the same as instr */ - char *opcode; /* buffer for opcode, min. 10 chars. */ - char *operands; /* operand buffer, min. 24 chars. */ - /* changed by disassembler: */ - unsigned char type; /* type of instruction, see below */ - unsigned char flags; /* additional flags */ - unsigned short sreg; /* register in load/store instructions */ - ppc_word displacement; /* branch- or load/store displacement */ - }; - -#define PPCINSTR_OTHER 0 /* no additional info for other instr. */ -#define PPCINSTR_BRANCH 1 /* branch dest. = PC+displacement */ -#define PPCINSTR_LDST 2 /* load/store instruction: displ(sreg) */ -#define PPCINSTR_IMM 3 /* 16-bit immediate val. in displacement */ - -#define PPCF_ILLEGAL (1<<0) /* illegal PowerPC instruction */ -#define PPCF_UNSIGNED (1<<1) /* unsigned immediate instruction */ -#define PPCF_SUPER (1<<2) /* supervisor level instruction */ -#define PPCF_64 (1<<3) /* 64-bit only instruction */ - - - /* ppc_disasm.o prototypes */ -#ifndef PPC_DISASM_C - extern ppc_word *PPC_Disassemble(struct DisasmPara_PPC *); -#endif - - - static const char *trap_condition[32] = { - NULL,"lgt","llt",NULL,"eq","lge","lle",NULL, - "gt",NULL,NULL,NULL,"ge",NULL,NULL,NULL, - "lt",NULL,NULL,NULL,"le",NULL,NULL,NULL, - "ne",NULL,NULL,NULL,NULL,NULL,NULL,NULL - }; - - static const char *cmpname[4] = { - "cmpw","cmpd","cmplw","cmpld" - }; - - static const char *b_ext[4] = { - "","l","a","la" - }; - - static const char *b_condition[8] = { - "ge","le","ne","ns","lt","gt","eq","so" - }; - - static const char *b_decr[16] = { - "nzf","zf",NULL,NULL,"nzt","zt",NULL,NULL, - "nz","z",NULL,NULL,"nz","z",NULL,NULL - }; - - static const char *regsel[2] = { - "","r" - }; - - static const char *oesel[2] = { - "","o" - }; - - static const char *rcsel[2] = { - "","." - }; - - static const char *ldstnames[] = { - "lwz","lwzu","lbz","lbzu","stw","stwu","stb","stbu","lhz","lhzu", - "lha","lhau","sth","sthu","lmw","stmw","lfs","lfsu","lfd","lfdu", - "stfs","stfsu","stfd","stfdu" - }; - - static const char *regnames[] = { - "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" - }; - - static const char *spr_name(int i) - { - static char def[8]; - - switch (i) - { - case 1: return "XER"; - case 8: return "LR"; - case 9: return "CTR"; - case 18: return "DSIR"; - case 19: return "DAR"; - case 22: return "DEC"; - case 25: return "SDR1"; - case 26: return "SRR0"; - case 27: return "SRR1"; - case 272: return "SPRG0"; - case 273: return "SPRG1"; - case 274: return "SPRG2"; - case 275: return "SPRG3"; - case 282: return "EAR"; - case 287: return "PVR"; - case 528: return "IBAT0U"; - case 529: return "IBAT0L"; - case 530: return "IBAT1U"; - case 531: return "IBAT1L"; - case 532: return "IBAT2U"; - case 533: return "IBAT2L"; - case 534: return "IBAT3U"; - case 535: return "IBAT3L"; - case 536: return "DBAT0U"; - case 537: return "DBAT0L"; - case 538: return "DBAT1U"; - case 539: return "DBAT1L"; - case 540: return "DBAT2U"; - case 541: return "DBAT2L"; - case 542: return "DBAT3U"; - case 543: return "DBAT3L"; - case 912: return "GQR0"; - case 913: return "GQR1"; - case 914: return "GQR2"; - case 915: return "GQR3"; - case 916: return "GQR4"; - case 917: return "GQR5"; - case 918: return "GQR6"; - case 919: return "GQR7"; - case 920: return "HID2"; - case 921: return "WPAR"; - case 922: return "DMA_U"; - case 923: return "DMA_L"; - case 924: return "ECID_U"; - case 925: return "ECID_M"; - case 926: return "ECID_L"; - case 936: return "UMMCR0"; - case 937: return "UPMC1"; - case 938: return "UPMC2"; - case 939: return "USIA"; - case 940: return "UMMCR1"; - case 941: return "UPMC3"; - case 942: return "UPMC4"; - case 943: return "USDA"; - case 952: return "MMCR0"; - case 953: return "PMC1"; - case 954: return "PMC2"; - case 955: return "SIA"; - case 956: return "MMCR1"; - case 957: return "PMC3"; - case 958: return "PMC4"; - case 959: return "SDA"; - case 1008: return "HID0"; - case 1009: return "HID1"; - case 1010: return "IABR"; - case 1011: return "HID4"; - case 1013: return "DABR"; - case 1017: return "L2CR"; - case 1019: return "ICTC"; - case 1020: return "THRM1"; - case 1021: return "THRM2"; - case 1022: return "THRM3"; - } - - sprintf(def, "%i", i); - return def; - } - - static void ierror(const char *errtxt,...) - /* display internal error and quit program */ - { - va_list vl; - - fprintf(stderr,"\nINTERNAL ERROR (PPC disassembler): "); - va_start(vl,errtxt); - vfprintf(stderr,errtxt,vl); - va_end(vl); - fprintf(stderr,".\nAborting.\n"); - exit(1); - } - - - static ppc_word swapda(ppc_word w) - { - return ((w&0xfc00ffff)|((w&PPCAMASK)<<5)|((w&PPCDMASK)>>5)); - } - - - static ppc_word swapab(ppc_word w) - { - return ((w&0xffe007ff)|((w&PPCBMASK)<<5)|((w&PPCAMASK)>>5)); - } - - - static void ill(struct DisasmPara_PPC *dp,ppc_word in) - { - if (in == 0) { - strcpy(dp->opcode, ""); - strcpy(dp->operands, "---"); - } else { - strcpy(dp->opcode, "( ill )"); - sprintf(dp->operands, "%08x", in); - } - - dp->flags |= PPCF_ILLEGAL; - } - - - static void imm(struct DisasmPara_PPC *dp,ppc_word in,int uimm,int type,int hex) - /* Generate immediate instruction operand. */ - /* type 0: D-mode, D,A,imm */ - /* type 1: S-mode, A,S,imm */ - /* type 2: S/D register is ignored (trap,cmpi) */ - /* type 3: A register is ignored (li) */ - { - int i = (int)(in & 0xffff); - - dp->type = PPCINSTR_IMM; - if (!uimm) { - if (i > 0x7fff) - i -= 0x10000; - } - else - dp->flags |= PPCF_UNSIGNED; - dp->displacement = i; - - switch (type) { - case 0: - sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETD(in)],regnames[(int)PPCGETA(in)],i); - break; - case 1: - if (hex) - sprintf(dp->operands,"%s, %s, 0x%.4X",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); - else - sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); - break; - case 2: - sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETA(in)],i); - break; - case 3: - if (hex) - sprintf(dp->operands,"%s, 0x%.4X",regnames[(int)PPCGETD(in)],i); - else - sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETD(in)],i); - break; - default: - ierror("imm(): Wrong type"); - break; - } - } - - - static void ra_rb(char *s,ppc_word in) - { - sprintf(s,"%s, %s",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETB(in)]); - } - - - static char *rd_ra_rb(char *s,ppc_word in,int mask) - { - static const char *fmt = "%s, "; - - if (mask) { - if (mask & 4) - s += sprintf(s,fmt,regnames[(int)PPCGETD(in)]); - if (mask & 2) - s += sprintf(s,fmt,regnames[(int)PPCGETA(in)]); - if (mask & 1) - s += sprintf(s,fmt,regnames[(int)PPCGETB(in)]); - *--s = '\0'; - *--s = '\0'; - } - else - *s = '\0'; - return (s); - } - - - static char *fd_ra_rb(char *s,ppc_word in,int mask) - { - static const char *ffmt = "f%d,"; - static const char *rfmt = "%s,"; - - if (mask) { - if (mask & 4) - s += sprintf(s,ffmt,(int)PPCGETD(in)); - if (mask & 2) - s += sprintf(s,rfmt,regnames[(int)PPCGETA(in)]); - if (mask & 1) - s += sprintf(s,rfmt,regnames[(int)PPCGETB(in)]); - *--s = '\0'; - } - else - *s = '\0'; - return (s); - } - - - static void trapi(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) - { - const char *cnd; - - if ((cnd = trap_condition[PPCGETD(in)]) != NULL) { - dp->flags |= dmode; - sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); - imm(dp,in,0,2,0); - } - else - ill(dp,in); - } - - - static void cmpi(struct DisasmPara_PPC *dp,ppc_word in,int uimm) - { - char *oper = dp->operands; - int i = (int)PPCGETL(in); - - if (i < 2) { - if (i) - dp->flags |= PPCF_64; - sprintf(dp->opcode,"%si",cmpname[uimm*2+i]); - if ((i = (int)PPCGETCRD(in))) { - sprintf(oper,"cr%c,",'0'+i); - dp->operands += 4; - } - imm(dp,in,uimm,2,0); - dp->operands = oper; - } - else - ill(dp,in); - } - - - static void addi(struct DisasmPara_PPC *dp,ppc_word in,const char *ext) - { - if ((in&0x08000000) && !PPCGETA(in)) { - sprintf(dp->opcode,"l%s",ext); /* li, lis */ - if (!strcmp(ext, "i")) - imm(dp,in,0,3,0); - else - imm(dp,in,1,3,1); - } - else { - sprintf(dp->opcode,"%s%s",(in&0x8000)?"sub":"add",ext); - if (in & 0x8000) - in = (in^0xffff) + 1; - imm(dp,in,1,0,0); - } - } - - - static int branch(struct DisasmPara_PPC *dp,ppc_word in, const char *bname,int aform,int bdisp) - /* build a branch instr. and return number of chars written to operand */ - { - int bo = (int)PPCGETD(in); - int bi = (int)PPCGETA(in); - char y = (char)(bo & 1); - int opercnt = 0; - const char *ext = b_ext[aform*2+(int)(in&1)]; - - if (bdisp < 0) - y ^= 1; - y = y ? '+':'-'; - - if (bo & 4) { - /* standard case - no decrement */ - if (bo & 16) { - /* branch always */ - if (PPCGETIDX(in) != 16) { - sprintf(dp->opcode,"b%s%s",bname,ext); - } - else { - sprintf(dp->opcode,"bc%s",ext); - opercnt = sprintf(dp->operands,"%d, %d",bo,bi); - } - } - else { - /* branch conditional */ - sprintf(dp->opcode,"b%s%s%s%c",b_condition[((bo&8)>>1)+(bi&3)], - bname,ext,y); - if (bi >= 4) - opercnt = sprintf(dp->operands,"cr%d",bi>>2); - } - } - - else { - /* CTR is decremented and checked */ - sprintf(dp->opcode,"bd%s%s%s%c",b_decr[bo>>1],bname,ext,y); - if (!(bo & 16)) - opercnt = sprintf(dp->operands,"%d",bi); - } - - return (opercnt); - } - - - static void bc(struct DisasmPara_PPC *dp,ppc_word in) - { - unsigned int d = (int)(in & 0xfffc); - int offs; - char *oper = dp->operands; - - if (d & 0x8000) d |= 0xffff0000; - - if ((offs = branch(dp,in,"",(in&2)?1:0,d))) { - oper += offs; - *oper++ = ','; - } - if (in & 2) /* AA ? */ - sprintf(dp->operands,"->0x%.8X",(unsigned int)d); - else - sprintf(oper,"->0x%.8X",(unsigned int)(*dp->iaddr) + d); - dp->type = PPCINSTR_BRANCH; - dp->displacement = (ppc_word)d; - } - - - static void bli(struct DisasmPara_PPC *dp,ppc_word in) - { - unsigned int d = (unsigned int)(in & 0x3fffffc); - - if (d & 0x02000000) d |= 0xfc000000; - - sprintf(dp->opcode,"b%s",b_ext[in&3]); - if (in & 2) /* AA ? */ - sprintf(dp->operands,"->0x%.8X",(unsigned int)d); - else - sprintf(dp->operands,"->0x%.8X",(unsigned int)(*dp->iaddr) + d); - dp->type = PPCINSTR_BRANCH; - dp->displacement = (ppc_word)d; - } - - - static void mcrf(struct DisasmPara_PPC *dp,ppc_word in,char c) - { - if (!(in & 0x0063f801)) { - sprintf(dp->opcode,"mcrf%c",c); - sprintf(dp->operands,"cr%d, cr%d",(int)PPCGETCRD(in),(int)PPCGETCRA(in)); - } - else - ill(dp,in); - } - - - static void crop(struct DisasmPara_PPC *dp,ppc_word in,const char *n1,const char *n2) - { - int crd = (int)PPCGETD(in); - int cra = (int)PPCGETA(in); - int crb = (int)PPCGETB(in); - - if (!(in & 1)) { - sprintf(dp->opcode,"cr%s",(cra==crb && n2)?n2:n1); - if (cra == crb && n2) - sprintf(dp->operands,"%d, %d",crd,cra); - else - sprintf(dp->operands,"%d, %d, %d",crd,cra,crb); - } - else - ill(dp,in); - } - - - static void nooper(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - unsigned char dmode) - { - if (in & (PPCDMASK|PPCAMASK|PPCBMASK|1)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - strcpy(dp->opcode,name); - } - } - - - static unsigned int Helper_Rotate_Mask(int r, int mb, int me) - { - //first make 001111111111111 part - unsigned int begin = 0xFFFFFFFF >> mb; - //then make 000000000001111 part, which is used to flip the bits of the first one - unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; - //do the bitflip - unsigned int mask = begin ^ end; - //and invert if backwards - if (me < mb) - mask = ~mask; - //rotate the mask so it can be applied to source reg - //return _rotl(mask, 32 - r); - return (mask << (32 - r)) | (mask >> r); - } - - - static void rlw(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)PPCGETB(in); - int mb = (int)PPCGETC(in); - int me = (int)PPCGETM(in); - sprintf(dp->opcode,"rlw%s%c",name,in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %s%d, %d, %d (%08x)",regnames[a],regnames[s],regsel[i],bsh,mb,me,Helper_Rotate_Mask(bsh, mb, me)); - } - - - static void ori(struct DisasmPara_PPC *dp,ppc_word in,const char *name) - { - strcpy(dp->opcode,name); - imm(dp,in,1,1,1); - } - - - static void rld(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = i ? (int)PPCGETB(in) : (int)(((in&2)<<4)+PPCGETB(in)); - int m = (int)(in&0x7e0)>>5; - - dp->flags |= PPCF_64; - sprintf(dp->opcode,"rld%s%c",name,in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %s%d, %d",regnames[a],regnames[s],regsel[i],bsh,m); - } - - - static void cmp(struct DisasmPara_PPC *dp,ppc_word in) - { - char *oper = dp->operands; - int i = (int)PPCGETL(in); - - if (i < 2) { - if (i) - dp->flags |= PPCF_64; - strcpy(dp->opcode,cmpname[((in&PPCIDX2MASK)?2:0)+i]); - if ((i = (int)PPCGETCRD(in))) - oper += sprintf(oper,"cr%c,",'0'+i); - ra_rb(oper,in); - } - else - ill(dp,in); - } - - - static void trap(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) - { - const char *cnd; - int to = (int)PPCGETD(in); - - if ((cnd = trap_condition[to])) { - dp->flags |= dmode; - sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); - ra_rb(dp->operands,in); - } - else { - if (to == 31) { - if (dmode) { - dp->flags |= dmode; - strcpy(dp->opcode,"td"); - strcpy(dp->operands,"31,0,0"); - } - else - strcpy(dp->opcode,"trap"); - } - else - ill(dp,in); - } - } - - - static void dab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask, - int smode,int chkoe,int chkrc,unsigned char dmode) - /* standard instruction: xxxx rD,rA,rB */ - { - if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - if (smode) - in = swapda(in); /* rA,rS,rB */ - sprintf(dp->opcode,"%s%s%s",name, - oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); - rd_ra_rb(dp->operands,in,mask); - } - } - - - static void rrn(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - int smode,int chkoe,int chkrc,unsigned char dmode) - /* Last operand is no register: xxxx rD,rA,NB */ - { - char *s; - - if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - if (smode) - in = swapda(in); /* rA,rS,NB */ - sprintf(dp->opcode,"%s%s%s",name, - oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); - s = rd_ra_rb(dp->operands,in,6); - sprintf(s,",%d",(int)PPCGETB(in)); - } - } - - - static void mtcr(struct DisasmPara_PPC *dp,ppc_word in) - { - int s = (int)PPCGETD(in); - int crm = (int)(in&0x000ff000)>>12; - char *oper = dp->operands; - - if (in & 0x00100801) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"mtcr%c",crm==0xff?'\0':'f'); - if (crm != 0xff) - oper += sprintf(oper,"0x%02x,",crm); - sprintf(oper,"%s",regnames[s]); - } - } - - - static void msr(struct DisasmPara_PPC *dp,ppc_word in,int smode) - { - int s = (int)PPCGETD(in); - int sr = (int)(in&0x000f0000)>>16; - - if (in & 0x0010f801) { - ill(dp,in); - } - else { - dp->flags |= PPCF_SUPER; - sprintf(dp->opcode,"m%csr",smode?'t':'f'); - if (smode) - sprintf(dp->operands,"%d, %s",sr,regnames[s]); - else - sprintf(dp->operands,"%s, %d",regnames[s],sr); - } - } - - - static void mspr(struct DisasmPara_PPC *dp,ppc_word in,int smode) - { - int d = (int)PPCGETD(in); - int spr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); - int fmt = 0; - const char *x; - - if (in & 1) { - ill(dp,in); - } - - else { - if (spr!=1 && spr!=8 && spr!=9) - dp->flags |= PPCF_SUPER; - switch (spr) { - case 1: - x = "xer"; - break; - case 8: - x = "lr"; - break; - case 9: - x = "ctr"; - break; - default: - x = "spr"; - fmt = 1; - break; - } - - sprintf(dp->opcode,"m%c%s",smode?'t':'f',x); - if (fmt) { - if (smode) - sprintf(dp->operands,"%s, %s",spr_name(spr),regnames[d]); - else - sprintf(dp->operands,"%s, %s",regnames[d],spr_name(spr)); - } - else - sprintf(dp->operands,"%s",regnames[d]); - } - } - - - static void mtb(struct DisasmPara_PPC *dp,ppc_word in) - { - int d = (int)PPCGETD(in); - int tbr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); - char *s = dp->operands; - char x; - - if (in & 1) { - ill(dp,in); - } - - else { - s += sprintf(s,"%s",regnames[d]); - switch (tbr) { - case 268: - x = 'l'; - break; - case 269: - x = 'u'; - break; - default: - x = '\0'; - dp->flags |= PPCF_SUPER; - sprintf(s,",%d",tbr); - break; - } - sprintf(dp->opcode,"mftb%c",x); - } - } - - - static void sradi(struct DisasmPara_PPC *dp,ppc_word in) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)(((in&2)<<4)+PPCGETB(in)); - - dp->flags |= PPCF_64; - sprintf(dp->opcode,"sradi%c",in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %d",regnames[a],regnames[s],bsh); - } - - static const char *ldst_offs(unsigned int val) - { - static char buf[8]; - - if (val == 0) - { - return "0"; - } - else - { - if (val & 0x8000) - { - sprintf(buf, "-0x%.4X", ((~val) & 0xffff) + 1); - } - else - { - sprintf(buf, "0x%.4X", val); - } - - return buf; - } - } - - static void ldst(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - char reg,unsigned char dmode) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int d = (ppc_word)(in & 0xffff); - - dp->type = PPCINSTR_LDST; - dp->flags |= dmode; - dp->sreg = (short)a; - // if (d >= 0x8000) - // d -= 0x10000; - dp->displacement = (ppc_word)d; - strcpy(dp->opcode,name); - if (reg == 'r') - { - sprintf(dp->operands,"%s, %s (%s)", regnames[s], ldst_offs(d), regnames[a]); - } - else - { - sprintf(dp->operands,"%c%d, %s (%s)",reg,s, ldst_offs(d), regnames[a]); - } - } - - - static void fdabc(struct DisasmPara_PPC *dp,ppc_word in, const char *name, - int mask,unsigned char dmode) - /* standard floating point instruction: xxxx fD,fA,fC,fB */ - { - static const char *fmt = "f%d,"; - char *s = dp->operands; - int err = 0; - - dp->flags |= dmode; - sprintf(dp->opcode,"f%s%s",name,rcsel[in&1]); - s += sprintf(s,fmt,(int)PPCGETD(in)); - if (mask & 4) - s += sprintf(s,fmt,(int)PPCGETA(in)); - else - err |= (int)PPCGETA(in); - if (mask & 2) - s += sprintf(s,fmt,(int)PPCGETC(in)); - else if (PPCGETC(in)) - err |= (int)PPCGETC(in); - if (mask & 1) - s += sprintf(s,fmt,(int)PPCGETB(in)); - else if (!(mask&8)) - err |= (int)PPCGETB(in); - *(s-1) = '\0'; - if (err) - ill(dp,in); - } - - static void fmr(struct DisasmPara_PPC *dp,ppc_word in) - { - sprintf(dp->opcode, "fmr%s", rcsel[in&1]); - sprintf(dp->operands, "f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in)); - } - - static void fdab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask) - /* indexed float instruction: xxxx fD,rA,rB */ - { - strcpy(dp->opcode,name); - fd_ra_rb(dp->operands,in,mask); - } - - - static void fcmp(struct DisasmPara_PPC *dp,ppc_word in,char c) - { - if (in & 0x00600001) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"fcmp%c",c); - sprintf(dp->operands,"cr%d,f%d,f%d",(int)PPCGETCRD(in), - (int)PPCGETA(in),(int)PPCGETB(in)); - } - } - - - static void mtfsb(struct DisasmPara_PPC *dp,ppc_word in,int n) - { - if (in & (PPCAMASK|PPCBMASK)) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"mtfsb%d%s",n,rcsel[in&1]); - sprintf(dp->operands,"%d",(int)PPCGETD(in)); - } - } - - - ////////////////////////////////////////////////////////////////////////////////// - //PAIRED - ////////////////////////////////////////////////////////////////////////////////// - - /* - sprintf(buf, "psq_lx", FD); - sprintf(buf, "psq_stx", FD); - sprintf(buf, "psq_lux", FD); - sprintf(buf, "psq_stux", FD); - */ -#define RA ((inst >> 16) & 0x1f) -#define RB ((inst >> 11) & 0x1f) -#define RC ((inst >> 6) & 0x1f) -#define RD ((inst >> 21) & 0x1f) -#define RS ((inst >> 21) & 0x1f) -#define FA ((inst >> 16) & 0x1f) -#define FB ((inst >> 11) & 0x1f) -#define FC ((inst >> 6) & 0x1f) -#define FD ((inst >> 21) & 0x1f) -#define FS ((inst >> 21) & 0x1f) -#define IMM (inst & 0xffff) -#define UIMM (inst & 0xffff) -#define OFS (inst & 0xffff) -#define OPCD ((inst >> 26) & 0x3f) -#define XO_10 ((inst >> 1) & 0x3ff) -#define XO_9 ((inst >> 1) & 0x1ff) -#define XO_5 ((inst >> 1) & 0x1f) -#define Rc (inst & 1) -#define SH ((inst >> 11) & 0x1f) -#define MB ((inst >> 6) & 0x1f) -#define ME ((inst >> 1) & 0x1f) -#define OE ((inst >> 10) & 1) -#define TO ((inst >> 21) & 0x1f) -#define CRFD ((inst >> 23) & 0x7) -#define CRFS ((inst >> 18) & 0x7) -#define CRBD ((inst >> 21) & 0x1f) -#define CRBA ((inst >> 16) & 0x1f) -#define CRBB ((inst >> 11) & 0x1f) -#define L ((inst >> 21) & 1) -#define NB ((inst >> 11) & 0x1f) -#define AA ((inst >> 1) & 1) -#define LK (inst & 1) -#define LI ((inst >> 2) & 0xffffff) -#define BO ((inst >> 21) & 0x1f) -#define BI ((inst >> 16) & 0x1f) -#define BD ((inst >> 2) & 0x3fff) - -#define MTFSFI_IMM ((inst >> 12) & 0xf) -#define FM ((inst >> 17) & 0xff) -#define SR ((inst >> 16) & 0xf) -#define SPR ((inst >> 11) & 0x3ff) -#define TBR ((inst >> 11) & 0x3ff) -#define CRM ((inst >> 12) & 0xff) - - inline int SEX12(unsigned int x) - { - return x & 0x800 ? (x|0xFFFFF000) : x; - } - - static void ps(struct DisasmPara_PPC *dp,ppc_word inst) - { - char *op = dp->opcode; - char *pr = dp->operands; - switch ((inst>>1)&0x1F) - { - case 6: - strcpy(op, "ps_lux"); - sprintf(pr, "p%u, (r%u + r%u)", FD, RA, RB); - return; - - case 18: - strcpy(op, "ps_div"); - sprintf(pr, "p%u, p%u/p%u", FD, FA, FB); - return; - case 20: - strcpy(op, "ps_sub"); - sprintf(pr, "p%u, p%u-p%u", FD, FA, FB); - return; - case 21: - strcpy(op, "ps_add"); - sprintf(pr, "p%u, p%u+p%u", FD, FA, FB); - return; - case 23: - strcpy(op, "ps_sel"); - sprintf(pr, "p%u>=0?p%u:p%u", FD, FA, FC); - return; - case 24: - strcpy(op, "ps_res"); - sprintf(pr, "p%u, (1/p%u)", FD, FB); - return; - - case 25: - strcpy(op, "ps_mul"); - sprintf(pr, "p%u, p%u*p%u", FD, FA, FC); - return; - - case 26: //rsqrte - strcpy(op, "ps_rsqrte"); - sprintf(pr, "p%u, p%u", FD, FB); - return; - case 28: //msub - strcpy(op, "ps_msub"); - sprintf(pr, "p%u, p%u*p%u-p%u", FD, FA, FC, FB); - return; - case 29: //madd - strcpy(op, "ps_madd"); - sprintf(pr, "p%u, p%u*p%u+p%u", FD, FA, FC, FB); - return; - case 30: //nmsub - strcpy(op, "ps_nmsub"); - sprintf(pr, "p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); - return; - case 31: //nmadd - strcpy(op, "ps_nmadd"); - sprintf(pr, "p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); - return; - case 10: - strcpy(op, "ps_sum0"); - sprintf(pr, "p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); - return; - case 11: - strcpy(op, "ps_sum1"); - sprintf(pr, "p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); - return; - case 12: - strcpy(op, "ps_muls0"); - sprintf(pr, "p%u, p%u*p%u[0]", FD, FA, FC); - return; - case 13: - strcpy(op, "ps_muls1"); - sprintf(pr, "p%u, p%u*p%u[1]", FD, FA, FC); - return; - case 14: - strcpy(op, "ps_madds0"); - sprintf(pr, "p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); - return; - case 15: - strcpy(op, "ps_madds1"); - sprintf(pr, "p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); - return; - } - - switch ((inst>>1)&0x3FF) - { - //10-bit suckers (?) - case 40: //nmadd - strcpy(op, "ps_neg"); - sprintf(pr, "p%u, -p%u", FD, FB); - return; - case 72: //nmadd - strcpy(op, "ps_mr"); - sprintf(pr, "p%u, p%u", FD, FB); - return; - case 136: - strcpy(op, "ps_nabs"); - sprintf(pr, "p%u, -|p%u|", FD, FB); - return; - case 264: - strcpy(op, "ps_abs"); - sprintf(pr, "p%u, |p%u|", FD, FB); - return; - case 0: - strcpy(op, "ps_cmpu0"); - sprintf(pr, "ps_cmpu0"); - return; - case 32: - strcpy(op,"ps_cmpq0"); - sprintf(pr, "ps_cmpo0"); - return; - case 64: - strcpy(op,"ps_cmpu1"); - sprintf(pr, "ps_cmpu1"); - return; - case 96: - strcpy(op,"ps_cmpo1"); - sprintf(pr, "ps_cmpo1"); - return; - case 528: - strcpy(op,"ps_merge00"); - sprintf(pr, "p%u, p%u[0],p%u[0]", FD, FA, FB); - return; - case 560: - strcpy(op,"ps_merge01"); - sprintf(pr, "p%u, p%u[0],p%u[1]", FD, FA, FB); - return; - case 592: - strcpy(op,"ps_merge10"); - sprintf(pr, "p%u, p%u[1],p%u[0]", FD, FA, FB); - return; - case 624: - strcpy(op,"ps_merge11"); - sprintf(pr, "p%u, p%u[1],p%u[1]", FD, FA, FB); - return; - case 1014: - strcpy(op,"dcbz_l"); - *pr = '\0'; - return; - } - - // default: - sprintf(op, "ps_%i",((inst>>1)&0x1f)); - strcpy(pr,"---"); - return; - } - - static void ps_mem(struct DisasmPara_PPC *dp,ppc_word inst) - { - char *op = dp->opcode; - char *pr = dp->operands; - switch (PPCGETIDX(inst)) - { - case 56: - strcpy(op,"psq_l"); - sprintf(pr, "p%u, %i(r%u)", RS, SEX12(inst&0xFFF), RA); - break; - case 57: - strcpy(op,"psq_lu"); - *pr = '\0'; - break; - case 60: - strcpy(op,"psq_st"); - sprintf(pr, "%i(r%u), p%u", SEX12(inst&0xFFF), RA, RS); - break; - case 61: - strcpy(op,"psq_stu"); - sprintf(pr, "r%u, p%u ?", RA, RS); - break; - } - } - - - ppc_word *PPC_Disassemble(struct DisasmPara_PPC *dp) - /* Disassemble PPC instruction and return a pointer to the next */ - /* instruction, or NULL if an error occured. */ - { - ppc_word in = *(dp->instr); - if (!dp->opcode || !dp->operands) - return NULL; /* no buffers */ - - #if LITTLEENDIAN - in = (in & 0xff)<<24 | (in & 0xff00)<<8 | (in & 0xff0000)>>8 | - (in & 0xff000000)>>24; - #endif - dp->type = PPCINSTR_OTHER; - dp->flags = 0; - *(dp->operands) = 0; - - switch (PPCGETIDX(in)) - { - case 0: - { - int block = in & 0x3FFFFFF; - if (block) { - sprintf(dp->opcode, "JITblock"); - sprintf(dp->operands, "%i", block); - } else { - strcpy(dp->opcode, ""); - strcpy(dp->operands, "---"); - } - } - break; - case 1: - sprintf(dp->opcode,"HLE"); - //HLE call - break; - case 2: - trapi(dp,in,PPCF_64); /* tdi */ - break; - - case 3: - trapi(dp,in,0); /* twi */ - break; - case 4: - ps(dp,in); - break; - case 56: - case 57: - case 60: - case 61: - ps_mem(dp,in); - break; - - - case 7: - strcpy(dp->opcode,"mulli"); - imm(dp,in,0,0,0); - break; - - case 8: - strcpy(dp->opcode,"subfic"); - imm(dp,in,0,0,0); - break; - - case 10: - cmpi(dp,in,1); /* cmpli */ - break; - - case 11: - cmpi(dp,in,0); /* cmpi */ - break; - - case 12: - addi(dp,in,"ic"); /* addic */ - break; - - case 13: - addi(dp,in,"ic."); /* addic. */ - break; - - case 14: - addi(dp,in,"i"); /* addi */ - break; - - case 15: - addi(dp,in,"is"); /* addis */ - break; - - case 16: - bc(dp,in); - break; - - case 17: - if ((in & ~PPCIDXMASK) == 2) - strcpy(dp->opcode,"sc"); - else - ill(dp,in); - break; - - case 18: - bli(dp,in); - break; - - case 19: - switch (PPCGETIDX2(in)) { - case 0: - mcrf(dp,in,'\0'); /* mcrf */ - break; - - case 16: - branch(dp,in,"lr",0,0); /* bclr */ - break; - - case 33: - crop(dp,in,"nor","not"); /* crnor */ - break; - - case 50: - nooper(dp,in,"rfi",PPCF_SUPER); - break; - - case 129: - crop(dp,in,"andc",NULL); /* crandc */ - break; - - case 150: - nooper(dp,in,"isync",0); - break; - - case 193: - crop(dp,in,"xor","clr"); /* crxor */ - break; - - case 225: - crop(dp,in,"nand",NULL); /* crnand */ - break; - - case 257: - crop(dp,in,"and",NULL); /* crand */ - break; - - case 289: - crop(dp,in,"eqv","set"); /* creqv */ - break; - - case 417: - crop(dp,in,"orc",NULL); /* crorc */ - break; - - case 449: - crop(dp,in,"or","move"); /* cror */ - break; - - case 528: - branch(dp,in,"ctr",0,0); /* bcctr */ - break; - - default: - ill(dp,in); - break; - } - break; - - case 20: - rlw(dp,in,"imi",0); /* rlwimi */ - break; - - case 21: - rlw(dp,in,"inm",0); /* rlwinm */ - break; - - case 23: - rlw(dp,in,"nm",1); /* rlwnm */ - break; - - case 24: - if (in & ~PPCIDXMASK) - ori(dp,in,"ori"); - else - strcpy(dp->opcode,"nop"); - break; - - case 25: - ori(dp,in,"oris"); - break; - - case 26: - ori(dp,in,"xori"); - break; - - case 27: - ori(dp,in,"xoris"); - break; - - case 28: - ori(dp,in,"andi."); - break; - - case 29: - ori(dp,in,"andis."); - break; - - case 30: - switch (in & 0x1c) { - case 0: - rld(dp,in,"icl",0); /* rldicl */ - break; - case 1: - rld(dp,in,"icr",0); /* rldicr */ - break; - case 2: - rld(dp,in,"ic",0); /* rldic */ - break; - case 3: - rld(dp,in,"imi",0); /* rldimi */ - break; - case 4: - rld(dp,in,in&2?"cl":"cr",1); /* rldcl, rldcr */ - break; - default: - ill(dp,in); - break; - } - break; - - case 31: - switch (PPCGETIDX2(in)) { - case 0: - case 32: - if (in & 1) - ill(dp,in); - else - cmp(dp,in); /* cmp, cmpl */ - break; - - case 4: - if (in & 1) - ill(dp,in); - else - trap(dp,in,0); /* tw */ - break; - - case 8: - case (PPCOE>>1)+8: - dab(dp,swapab(in),"subc",7,0,1,-1,0); - break; - - case 9: - dab(dp,in,"mulhdu",7,0,0,-1,PPCF_64); - break; - - case 10: - case (PPCOE>>1)+10: - dab(dp,in,"addc",7,0,1,-1,0); - break; - - case 11: - dab(dp,in,"mulhwu",7,0,0,-1,0); - break; - - case 19: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mfcr",4,0,0,0,0); - break; - - case 20: - dab(dp,in,"lwarx",7,0,0,0,0); - break; - - case 21: - dab(dp,in,"ldx",7,0,0,0,PPCF_64); - break; - - case 23: - dab(dp,in,"lwzx",7,0,0,0,0); - break; - - case 24: - dab(dp,in,"slw",7,1,0,-1,0); - break; - - case 26: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"cntlzw",6,1,0,-1,0); - break; - - case 27: - dab(dp,in,"sld",7,1,0,-1,PPCF_64); - break; - - case 28: - dab(dp,in,"and",7,1,0,-1,0); - break; - - case 40: - case (PPCOE>>1)+40: - dab(dp,swapab(in),"sub",7,0,1,-1,0); - break; - - case 53: - dab(dp,in,"ldux",7,0,0,0,PPCF_64); - break; - - case 54: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbst",3,0,0,0,0); - break; - - case 55: - dab(dp,in,"lwzux",7,0,0,0,0); - break; - - case 58: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"cntlzd",6,1,0,-1,PPCF_64); - break; - - case 60: - dab(dp,in,"andc",7,1,0,-1,0); - break; - - case 68: - trap(dp,in,PPCF_64); /* td */ - break; - - case 73: - dab(dp,in,"mulhd",7,0,0,-1,PPCF_64); - break; - - case 75: - dab(dp,in,"mulhw",7,0,0,-1,0); - break; - - case 83: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mfmsr",4,0,0,0,PPCF_SUPER); - break; - - case 84: - dab(dp,in,"ldarx",7,0,0,0,PPCF_64); - break; - - case 86: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbf",3,0,0,0,0); - break; - - case 87: - dab(dp,in,"lbzx",7,0,0,0,0); - break; - - case 104: - case (PPCOE>>1)+104: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"neg",6,0,1,-1,0); - break; - - case 119: - dab(dp,in,"lbzux",7,0,0,0,0); - break; - - case 124: - if (PPCGETD(in) == PPCGETB(in)) - dab(dp,in,"not",6,1,0,-1,0); - else - dab(dp,in,"nor",7,1,0,-1,0); - break; - - case 136: - case (PPCOE>>1)+136: - dab(dp,in,"subfe",7,0,1,-1,0); - break; - - case 138: - case (PPCOE>>1)+138: - dab(dp,in,"adde",7,0,1,-1,0); - break; - - case 144: - mtcr(dp,in); - break; - - case 146: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mtmsr",4,0,0,0,PPCF_SUPER); - break; - - case 149: - dab(dp,in,"stdx",7,0,0,0,PPCF_64); - break; - - case 150: - dab(dp,in,"stwcx.",7,0,0,1,0); - break; - - case 151: - dab(dp,in,"stwx",7,0,0,0,0); - break; - - case 181: - dab(dp,in,"stdux",7,0,0,0,PPCF_64); - break; - - case 183: - dab(dp,in,"stwux",7,0,0,0,0); - break; - - case 200: - case (PPCOE>>1)+200: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"subfze",6,0,1,-1,0); - break; - - case 202: - case (PPCOE>>1)+202: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"addze",6,0,1,-1,0); - break; - - case 210: - msr(dp,in,1); /* mfsr */ - break; - - case 214: - dab(dp,in,"stdcx.",7,0,0,1,PPCF_64); - break; - - case 215: - dab(dp,in,"stbx",7,0,0,0,0); - break; - - case 232: - case (PPCOE>>1)+232: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"subfme",6,0,1,-1,0); - break; - - case 233: - case (PPCOE>>1)+233: - dab(dp,in,"mulld",7,0,1,-1,PPCF_64); - break; - - case 234: - case (PPCOE>>1)+234: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"addme",6,0,1,-1,0); - break; - - case 235: - case (PPCOE>>1)+235: - dab(dp,in,"mullw",7,0,1,-1,0); - break; - - case 242: - if (in & PPCAMASK) - ill(dp,in); - else - dab(dp,in,"mtsrin",5,0,0,0,PPCF_SUPER); - break; - - case 246: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbtst",3,0,0,0,0); - break; - - case 247: - dab(dp,in,"stbux",7,0,0,0,0); - break; - - case 266: - case (PPCOE>>1)+266: - dab(dp,in,"add",7,0,1,-1,0); - break; - - case 278: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbt",3,0,0,0,0); - break; - - case 279: - dab(dp,in,"lhzx",7,0,0,0,0); - break; - - case 284: - dab(dp,in,"eqv",7,1,0,-1,0); - break; - - case 306: - if (in & (PPCDMASK|PPCAMASK)) - ill(dp,in); - else - dab(dp,in,"tlbie",1,0,0,0,PPCF_SUPER); - break; - - case 310: - dab(dp,in,"eciwx",7,0,0,0,0); - break; - - case 311: - dab(dp,in,"lhzux",7,0,0,0,0); - break; - - case 316: - dab(dp,in,"xor",7,1,0,-1,0); - break; - - case 339: - mspr(dp,in,0); /* mfspr */ - break; - - case 341: - dab(dp,in,"lwax",7,0,0,0,PPCF_64); - break; - - case 343: - dab(dp,in,"lhax",7,0,0,0,0); - break; - - case 370: - nooper(dp,in,"tlbia",PPCF_SUPER); - break; - - case 371: - mtb(dp,in); /* mftb */ - break; - - case 373: - dab(dp,in,"lwaux",7,0,0,0,PPCF_64); - break; - - case 375: - dab(dp,in,"lhaux",7,0,0,0,0); - break; - - case 407: - dab(dp,in,"sthx",7,0,0,0,0); - break; - - case 412: - dab(dp,in,"orc",7,1,0,-1,0); - break; - - case 413: - sradi(dp,in); /* sradi */ - break; - - case 434: - if (in & (PPCDMASK|PPCAMASK)) - ill(dp,in); - else - dab(dp,in,"slbie",1,0,0,0,PPCF_SUPER|PPCF_64); - break; - - case 438: - dab(dp,in,"ecowx",7,0,0,0,0); - break; - - case 439: - dab(dp,in,"sthux",7,0,0,0,0); - break; - - case 444: - if (PPCGETD(in) == PPCGETB(in)) - dab(dp,in,"mr",6,1,0,-1,0); - else - dab(dp,in,"or",7,1,0,-1,0); - break; - - case 457: - case (PPCOE>>1)+457: - dab(dp,in,"divdu",7,0,1,-1,PPCF_64); - break; - - case 459: - case (PPCOE>>1)+459: - dab(dp,in,"divwu",7,0,1,-1,0); - break; - - case 467: - mspr(dp,in,1); /* mtspr */ - break; - - case 470: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbi",3,0,0,0,0); - break; - - case 476: - dab(dp,in,"nand",7,1,0,-1,0); - break; - - case 489: - case (PPCOE>>1)+489: - dab(dp,in,"divd",7,0,1,-1,PPCF_64); - break; - - case 491: - case (PPCOE>>1)+491: - dab(dp,in,"divw",7,0,1,-1,0); - break; - - case 498: - nooper(dp,in,"slbia",PPCF_SUPER|PPCF_64); - break; - - case 512: - if (in & 0x007ff801) - ill(dp,in); - else { - strcpy(dp->opcode,"mcrxr"); - sprintf(dp->operands,"cr%d",(int)PPCGETCRD(in)); - } - break; - - case 533: - dab(dp,in,"lswx",7,0,0,0,0); - break; - - case 534: - dab(dp,in,"lwbrx",7,0,0,0,0); - break; - - case 535: - fdab(dp,in,"lfsx",7); - break; - - case 536: - dab(dp,in,"srw",7,1,0,-1,0); - break; - - case 539: - dab(dp,in,"srd",7,1,0,-1,PPCF_64); - break; - - case 566: - nooper(dp,in,"tlbsync",PPCF_SUPER); - break; - - case 567: - fdab(dp,in,"lfsux",7); - break; - - case 595: - msr(dp,in,0); /* mfsr */ - break; - - case 597: - rrn(dp,in,"lswi",0,0,0,0); - break; - - case 598: - nooper(dp,in,"sync",PPCF_SUPER); - break; - - case 599: - fdab(dp,in,"lfdx",7); - break; - - case 631: - fdab(dp,in,"lfdux",7); - break; - - case 659: - if (in & PPCAMASK) - ill(dp,in); - else - dab(dp,in,"mfsrin",5,0,0,0,PPCF_SUPER); - break; - - case 661: - dab(dp,in,"stswx",7,0,0,0,0); - break; - - case 662: - dab(dp,in,"stwbrx",7,0,0,0,0); - break; - - case 663: - fdab(dp,in,"stfsx",7); - break; - - case 695: - fdab(dp,in,"stfsux",7); - break; - - case 725: - rrn(dp,in,"stswi",0,0,0,0); - break; - - case 727: - fdab(dp,in,"stfdx",7); - break; - - case 759: - fdab(dp,in,"stfdux",7); - break; - - case 790: - dab(dp,in,"lhbrx",7,0,0,0,0); - break; - - case 792: - dab(dp,in,"sraw",7,1,0,-1,0); - break; - - case 794: - dab(dp,in,"srad",7,1,0,-1,PPCF_64); - break; - - case 824: - rrn(dp,in,"srawi",1,0,-1,0); - break; - - case 854: - nooper(dp,in,"eieio",PPCF_SUPER); - break; - - case 918: - dab(dp,in,"sthbrx",7,0,0,0,0); - break; - - case 922: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsh",6,1,0,-1,0); - break; - - case 954: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsb",6,1,0,-1,0); - break; - - case 982: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"icbi",3,0,0,0,0); - break; - - case 983: - fdab(dp,in,"stfiwx",7); - break; - - case 986: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsw",6,1,0,-1,PPCF_64); - break; - - case 1014: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbz",3,0,0,0,0); - break; - - default: - ill(dp,in); - break; - } - break; - - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - case 38: - case 39: - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'r',0); - break; - - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'f',0); - break; - - case 58: - switch (in & 3) { - case 0: - ldst(dp,in&~3,"ld",'r',PPCF_64); - break; - case 1: - ldst(dp,in&~3,"ldu",'r',PPCF_64); - break; - case 2: - ldst(dp,in&~3,"lwa",'r',PPCF_64); - break; - default: - ill(dp,in); - break; - } - break; - - case 59: - switch (in & 0x3e) { - case 36: - fdabc(dp,in,"divs",5,0); - break; - - case 40: - fdabc(dp,in,"subs",5,0); - break; - - case 42: - fdabc(dp,in,"adds",5,0); - break; - - case 44: - fdabc(dp,in,"sqrts",2,0); - break; - - case 48: - fdabc(dp,in,"res",2,0); - break; - - case 50: - fdabc(dp,in,"muls",6,0); - break; - - case 56: - fdabc(dp,in,"msubs",7,0); - break; - - case 58: - fdabc(dp,in,"madds",7,0); - break; - - case 60: - fdabc(dp,in,"nmsubs",7,0); - break; - - case 62: - fdabc(dp,in,"nmadds",7,0); - break; - - default: - ill(dp,in); - break; - } - break; - - case 62: - switch (in & 3) { - case 0: - ldst(dp,in&~3,"std",'r',PPCF_64); - break; - case 1: - ldst(dp,in&~3,"stdu",'r',PPCF_64); - break; - default: - ill(dp,in); - break; - } - break; - - case 63: - if (in & 32) { - switch (in & 0x1e) { - case 4: - fdabc(dp,in,"div",5,0); - break; - - case 8: - fdabc(dp,in,"sub",5,0); - break; - - case 10: - fdabc(dp,in,"add",5,0); - break; - - case 12: - fdabc(dp,in,"sqrt",2,0); - break; - - case 14: - fdabc(dp,in,"sel",7,0); - break; - - case 18: - fdabc(dp,in,"mul",6,0); - break; - - case 20: - fdabc(dp,in,"rsqrte",1,0); - break; - - case 24: - fdabc(dp,in,"msub",7,0); - break; - - case 26: - fdabc(dp,in,"madd",7,0); - break; - - case 28: - fdabc(dp,in,"nmsub",7,0); - break; - - case 30: - fdabc(dp,in,"nmadd",7,0); - break; - - case 52: - sprintf(dp->opcode, "XXX dp 52"); - break; - - default: - ill(dp,in); - break; - } - } - else { - switch (PPCGETIDX2(in)) { - case 0: - fcmp(dp,in,'u'); - break; - - case 12: - fdabc(dp,in,"rsp",1,0); // 10 - break; - - case 14: - fdabc(dp,in,"ctiw",1,0); // 10 - break; - - case 15: - fdabc(dp,in,"ctiwz",1,0); // 10 - break; - - case 32: - fcmp(dp,in,'o'); - break; - - case 38: - mtfsb(dp,in,1); - break; - - case 40: - fdabc(dp,in,"neg",10,0); - break; - - case 64: - mcrf(dp,in,'s'); /* mcrfs */ - break; - - case 70: - mtfsb(dp,in,0); - break; - - case 72: - fmr(dp,in); - break; - - case 134: - if (!(in & 0x006f0800)) { - sprintf(dp->opcode,"mtfsfi%s",rcsel[in&1]); - sprintf(dp->operands,"cr%d,%d",(int)PPCGETCRD(in), - (int)(in & 0xf000)>>12); - } - else - ill(dp,in); - break; - - case 136: - fdabc(dp,in,"nabs",10,0); - break; - - case 264: - fdabc(dp,in,"abs",10,0); - break; - - case 583: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mffs",4,0,0,-1,0); - break; - - case 711: - if (!(in & 0x02010000)) { - sprintf(dp->opcode,"mtfsf%s",rcsel[in&1]); - sprintf(dp->operands,"0x%x,%d", - (unsigned)(in & 0x01fe)>>17,(int)PPCGETB(in)); - } - else - ill(dp,in); - break; - - case 814: - fdabc(dp,in,"fctid",10,PPCF_64); - break; - - case 815: - fdabc(dp,in,"fctidz",10,PPCF_64); - break; - - case 846: - fdabc(dp,in,"fcfid",10,PPCF_64); - break; - - default: - ill(dp,in); - break; - } - } - break; - - default: - ill(dp,in); - break; - } - return (dp->instr + 1); - } - -} // namespace - -// What were MS thinking? -#ifdef _WIN32 -#define snprintf _snprintf -#endif - -// simplified interface -void DisassembleGekko(unsigned int opcode, unsigned int curInstAddr, char *dest, int max_size) -{ - char opcodeStr[64], operandStr[64]; - PPCDisasm::DisasmPara_PPC dp; - unsigned int opc, adr; - - opc = opcode; - adr = curInstAddr; - - dp.opcode = opcodeStr; - dp.operands = operandStr; - dp.instr = (PPCDisasm::ppc_word *)&opc; - dp.iaddr = (PPCDisasm::ppc_word *)&adr; - - PPCDisasm::PPC_Disassemble(&dp); - - snprintf(dest, max_size, "%s\t%s", opcodeStr, operandStr); -} - - -static const char *gprnames[] = -{ - " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7", - " r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -}; - -const char *GetGPRName(unsigned int index) -{ - if (index < 32) - return gprnames[index]; - return 0; -} - - -static const char *fprnames[] = -{ - " f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7", - " f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" -}; - -const char *GetFPRName(unsigned int index) -{ - if (index < 32) - return fprnames[index]; - return 0; -} diff --git a/Externals/Bochs_disasm/PowerPCDisasm.h b/Externals/Bochs_disasm/PowerPCDisasm.h deleted file mode 100644 index d78186af94..0000000000 --- a/Externals/Bochs_disasm/PowerPCDisasm.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $VER: ppc_disasm V0.1 (23.05.1998) - * - * Disassembler module for the PowerPC microprocessor family - * Copyright (c) 1998-2000 Frank Wille - * - * ppc_disasm.c is freeware and may be freely redistributed as long as - * no modifications are made and nothing is charged for it. - * Non-commercial usage is allowed without any restrictions. - * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE - * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR. - * - * - * v0.1 (23.05.1998) phx - * First version, which implements all PowerPC instructions. - * v0.0 (09.05.1998) phx - * File created. - */ - - -// Yeah, this does not really belong in bochs_disasm, but hey, it's a disasm and it needed a common location... - -#ifndef _POWERPC_DISASM -#define _POWERPC_DISASM - -void DisassembleGekko(unsigned int opcode, unsigned int curInstAddr, char* dest, int max_size); -const char* GetGPRName(unsigned int index); -const char* GetFPRName(unsigned int index); - -#endif diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index d5974ecca6..246b5da0e7 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -3,6 +3,7 @@ set(SRCS BreakPoints.cpp ColorUtil.cpp FileSearch.cpp FileUtil.cpp + GekkoDisassembler.cpp Hash.cpp IniFile.cpp MathUtil.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 31d7bcaffd..106d925365 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -56,6 +56,7 @@ + @@ -94,6 +95,7 @@ + @@ -140,4 +142,4 @@ - + \ No newline at end of file diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 1afbcaa15f..3bb9f14958 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -70,6 +70,7 @@ Crypto + @@ -115,6 +116,7 @@ + diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index 26e0a3e2ee..96b4eec275 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -9,7 +9,7 @@ protected: virtual ~DebugInterface() {} public: - virtual void Disassemble(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} + virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; } virtual void GetRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} virtual int GetInstructionSize(int /*instruction*/) {return 1;} virtual bool IsAlive() {return true;} diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp new file mode 100644 index 0000000000..464d1cb4f5 --- /dev/null +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -0,0 +1,2299 @@ +/* $VER: ppc_disasm.c V1.5 (27.05.2009) + * + * Disassembler module for the PowerPC microprocessor family + * Copyright (c) 1998-2001,2009,2011 Frank Wille + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +// Modified for use with Dolphin + +#include + +#include "Common/CommonTypes.h" +#include "Common/GekkoDisassembler.h" +#include "Common/StringUtil.h" + +// version/revision +#define PPCDISASM_VER 1 +#define PPCDISASM_REV 6 + +// general defines +#define PPCIDXMASK 0xfc000000 +#define PPCIDX2MASK 0x000007fe +#define PPCDMASK 0x03e00000 +#define PPCAMASK 0x001f0000 +#define PPCBMASK 0x0000f800 +#define PPCCMASK 0x000007c0 +#define PPCMMASK 0x0000003e +#define PPCCRDMASK 0x03800000 +#define PPCCRAMASK 0x001c0000 +#define PPCLMASK 0x00600000 +#define PPCOE 0x00000400 +#define PPCVRC 0x00000400 +#define PPCDST 0x02000000 +#define PPCSTRM 0x00600000 + +#define PPCIDXSH 26 +#define PPCDSH 21 +#define PPCASH 16 +#define PPCBSH 11 +#define PPCCSH 6 +#define PPCMSH 1 +#define PPCCRDSH 23 +#define PPCCRASH 18 +#define PPCLSH 21 +#define PPCIDX2SH 1 + +#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH) +#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH) +#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH) +#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH) +#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH) +#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH) +#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH) +#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH) +#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH) +#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH) +#define PPCGETSTRM(x) (((x)&PPCSTRM)>>PPCDSH) + + +static const char* trap_condition[32] = { + nullptr, "lgt", "llt", nullptr, "eq", "lge", "lle", nullptr, + "gt", nullptr, nullptr, nullptr, "ge", nullptr, nullptr, nullptr, + "lt", nullptr, nullptr, nullptr, "le", nullptr, nullptr, nullptr, + "ne", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr +}; + +static const char* cmpname[4] = { + "cmpw", "cmpd", "cmplw", "cmpld" +}; + +static const char* b_ext[4] = { + "", "l", "a", "la" +}; + +static const char* b_condition[8] = { + "ge", "le", "ne", "ns", "lt", "gt", "eq", "so" +}; + +static const char* b_decr[16] = { + "nzf", "zf", nullptr, nullptr, "nzt", "zt", nullptr, nullptr, + "nz", "z", nullptr, nullptr, "nz", "z", nullptr, nullptr +}; + +static const char* regsel[2] = { + "", "r" +}; + +static const char* oesel[2] = { + "", "o" +}; + +static const char* rcsel[2] = { + "", "." +}; + +static const char* ldstnames[24] = { + "lwz", "lwzu", "lbz", "lbzu", "stw", "stwu", "stb", "stbu", "lhz", "lhzu", + "lha", "lhau", "sth", "sthu", "lmw", "stmw", "lfs", "lfsu", "lfd", "lfdu", + "stfs", "stfsu", "stfd", "stfdu" +}; + +static const char* regnames[32] = { + "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +// Initialize static class variables. +u32* GekkoDisassembler::m_instr = nullptr; +u32* GekkoDisassembler::m_iaddr = nullptr; +std::string GekkoDisassembler::m_opcode = ""; +std::string GekkoDisassembler::m_operands = ""; +unsigned char GekkoDisassembler::m_type = 0; +unsigned char GekkoDisassembler::m_flags = PPCF_ILLEGAL; +unsigned short GekkoDisassembler::m_sreg = 0; +u32 GekkoDisassembler::m_displacement = 0; + + +static std::string spr_name(int i) +{ + switch (i) + { + case 1: return "XER"; + case 8: return "LR"; + case 9: return "CTR"; + case 18: return "DSIR"; + case 19: return "DAR"; + case 22: return "DEC"; + case 25: return "SDR1"; + case 26: return "SRR0"; + case 27: return "SRR1"; + case 272: return "SPRG0"; + case 273: return "SPRG1"; + case 274: return "SPRG2"; + case 275: return "SPRG3"; + case 282: return "EAR"; + case 287: return "PVR"; + case 528: return "IBAT0U"; + case 529: return "IBAT0L"; + case 530: return "IBAT1U"; + case 531: return "IBAT1L"; + case 532: return "IBAT2U"; + case 533: return "IBAT2L"; + case 534: return "IBAT3U"; + case 535: return "IBAT3L"; + case 536: return "DBAT0U"; + case 537: return "DBAT0L"; + case 538: return "DBAT1U"; + case 539: return "DBAT1L"; + case 540: return "DBAT2U"; + case 541: return "DBAT2L"; + case 542: return "DBAT3U"; + case 543: return "DBAT3L"; + case 912: return "GQR0"; + case 913: return "GQR1"; + case 914: return "GQR2"; + case 915: return "GQR3"; + case 916: return "GQR4"; + case 917: return "GQR5"; + case 918: return "GQR6"; + case 919: return "GQR7"; + case 920: return "HID2"; + case 921: return "WPAR"; + case 922: return "DMA_U"; + case 923: return "DMA_L"; + case 924: return "ECID_U"; + case 925: return "ECID_M"; + case 926: return "ECID_L"; + case 936: return "UMMCR0"; + case 937: return "UPMC1"; + case 938: return "UPMC2"; + case 939: return "USIA"; + case 940: return "UMMCR1"; + case 941: return "UPMC3"; + case 942: return "UPMC4"; + case 943: return "USDA"; + case 952: return "MMCR0"; + case 953: return "PMC1"; + case 954: return "PMC2"; + case 955: return "SIA"; + case 956: return "MMCR1"; + case 957: return "PMC3"; + case 958: return "PMC4"; + case 959: return "SDA"; + case 1008: return "HID0"; + case 1009: return "HID1"; + case 1010: return "IABR"; + case 1011: return "HID4"; + case 1013: return "DABR"; + case 1017: return "L2CR"; + case 1019: return "ICTC"; + case 1020: return "THRM1"; + case 1021: return "THRM2"; + case 1022: return "THRM3"; + } + + return StringFromFormat("%d", i); +} + + +static u32 swapda(u32 w) +{ + return ((w & 0xfc00ffff) | ((w&PPCAMASK) << 5) | ((w&PPCDMASK) >> 5)); +} + + +static u32 swapab(u32 w) +{ + return ((w & 0xffe007ff) | ((w&PPCBMASK) << 5) | ((w&PPCAMASK) >> 5)); +} + + +void GekkoDisassembler::ill(u32 in) +{ + if (in == 0) + { + m_opcode = ""; + m_operands = "---"; + } + else + { + m_opcode = "(ill)"; + m_operands = StringFromFormat("%08x", in); + } + + m_flags |= PPCF_ILLEGAL; +} + +// Generate immediate instruction operand. +// +// Type 0: D-mode, D,A,imm +// Type 1: S-mode, A,S,imm +// Type 2: S/D register is ignored (trap,cmpi) +// Type 3: A register is ignored (li) +std::string GekkoDisassembler::imm(u32 in, int uimm, int type, bool hex) +{ + int i = (int)(in & 0xffff); + + m_type = PPCINSTR_IMM; + + if (uimm == 0) + { + if (i > 0x7fff) + i -= 0x10000; + } + else + { + m_flags |= PPCF_UNSIGNED; + } + m_displacement = i; + + switch (type) + { + case 0: + return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETD(in)], regnames[(int)PPCGETA(in)], i); + + case 1: + if (hex) + return StringFromFormat("%s, %s, 0x%.4X", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i); + else + return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i); + + case 2: + return StringFromFormat("%s, %d", regnames[(int)PPCGETA(in)], i); + + case 3: + if (hex) + return StringFromFormat("%s, 0x%.4X", regnames[(int)PPCGETD(in)], i); + else + return StringFromFormat("%s, %d", regnames[(int)PPCGETD(in)], i); + + default: + return StringFromFormat("%s", "imm(): Wrong type"); + } +} + + +std::string GekkoDisassembler::ra_rb(u32 in) +{ + return StringFromFormat("%s, %s", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETB(in)]); +} + + +std::string GekkoDisassembler::rd_ra_rb(u32 in, int mask) +{ + std::string result; + + if (mask) + { + if (mask & 4) + result += StringFromFormat("%s, ", regnames[(int)PPCGETD(in)]); + if (mask & 2) + result += StringFromFormat("%s, ", regnames[(int)PPCGETA(in)]); + if (mask & 1) + result += StringFromFormat("%s, ", regnames[(int)PPCGETB(in)]); + + size_t pos = result.rfind(", "); + if (pos != std::string::npos) + { + result.erase(pos, result.length() - pos); + } + } + + return result; +} + + +std::string GekkoDisassembler::fd_ra_rb(u32 in, int mask) +{ + std::string result; + + if (mask) + { + if (mask & 4) + result += StringFromFormat("f%d,", (int)PPCGETD(in)); + if (mask & 2) + result += StringFromFormat("%s,", regnames[(int)PPCGETA(in)]); + if (mask & 1) + result += StringFromFormat("%s,", regnames[(int)PPCGETB(in)]); + + // Drop the trailing comma + result.pop_back(); + } + + return result; +} + + +void GekkoDisassembler::trapi(u32 in, unsigned char dmode) +{ + const char* cnd = trap_condition[PPCGETD(in)]; + + if (cnd != nullptr) + { + m_flags |= dmode; + m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); + m_operands = imm(in, 0, 2, false); + } + else + { + ill(in); + } +} + + +void GekkoDisassembler::cmpi(u32 in, int uimm) +{ + int i = (int)PPCGETL(in); + + if (i < 2) + { + if (i != 0) + m_flags |= PPCF_64; + + m_opcode = StringFromFormat("%si", cmpname[uimm * 2 + i]); + + i = (int)PPCGETCRD(in); + if (i != 0) + { + m_operands += StringFromFormat("cr%c,", '0' + i); + } + + m_operands += imm(in, uimm, 2, false); + } + else + { + ill(in); + } +} + + +void GekkoDisassembler::addi(u32 in, const std::string& ext) +{ + if ((in & 0x08000000) && !PPCGETA(in)) + { + m_opcode = StringFromFormat("l%s", ext.c_str()); // li, lis + + if (ext == "i") + m_operands = imm(in, 0, 3, false); + else + m_operands = imm(in, 1, 3, true); + } + else + { + m_opcode = StringFromFormat("%s%s", (in & 0x8000) ? "sub" : "add", ext.c_str()); + + if (in & 0x8000) + in = (in ^ 0xffff) + 1; + + m_operands = imm(in, 1, 0, false); + } +} + +// Build a branch instr. and return number of chars written to operand. +size_t GekkoDisassembler::branch(u32 in, const char* bname, int aform, int bdisp) +{ + int bo = (int)PPCGETD(in); + int bi = (int)PPCGETA(in); + char y = (char)(bo & 1); + const char* ext = b_ext[aform * 2 + (int)(in & 1)]; + + if (bdisp < 0) + y ^= 1; + y = (y != 0) ? '+' : '-'; + + if (bo & 4) + { + // standard case - no decrement + if (bo & 16) + { + // branch always + if (PPCGETIDX(in) != 16) + { + m_opcode = StringFromFormat("b%s%s", bname, ext); + } + else + { + m_opcode = StringFromFormat("bc%s", ext); + m_operands = StringFromFormat("%d, %d", bo, bi); + } + } + else // Branch conditional + { + m_opcode = StringFromFormat("b%s%s%s%c", b_condition[((bo & 8) >> 1) + (bi & 3)], bname, ext, y); + + if (bi >= 4) + { + m_operands = StringFromFormat("cr%d", bi >> 2); + } + } + } + else + { + // CTR is decremented and checked + m_opcode = StringFromFormat("bd%s%s%s%c", b_decr[bo >> 1], bname, ext, y); + + if ((bo & 16) == 0) + { + m_operands = StringFromFormat("%d", bi); + } + } + + return m_operands.length(); +} + + +void GekkoDisassembler::bc(u32 in) +{ + unsigned int d = (int)(in & 0xfffc); + + if (d & 0x8000) + d |= 0xffff0000; + + branch(in, "", (in & 2) ? 1 : 0, d); + + if (in & 2) // AA ? + m_operands = StringFromFormat("->0x%.8X", d); + else + m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d); + + m_type = PPCINSTR_BRANCH; + m_displacement = d; +} + + +void GekkoDisassembler::bli(u32 in) +{ + unsigned int d = (unsigned int)(in & 0x3fffffc); + + if (d & 0x02000000) + d |= 0xfc000000; + + m_opcode = StringFromFormat("b%s", b_ext[in & 3]); + + if (in & 2) // AA ? + m_operands = StringFromFormat("->0x%.8X", d); + else + m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d); + + m_type = PPCINSTR_BRANCH; + m_displacement = d; +} + + +void GekkoDisassembler::mcrf(u32 in, char c) +{ + if ((in & 0x0063f801) == 0) + { + m_opcode = StringFromFormat("mcrf%c", c); + m_operands = StringFromFormat("cr%d, cr%d", (int)PPCGETCRD(in), (int)PPCGETCRA(in)); + } + else + { + ill(in); + } +} + + +void GekkoDisassembler::crop(u32 in, const char* n1, const char* n2) +{ + int crd = (int)PPCGETD(in); + int cra = (int)PPCGETA(in); + int crb = (int)PPCGETB(in); + + if ((in & 1) == 0) + { + m_opcode = StringFromFormat("cr%s", (cra == crb && n2) ? n2 : n1); + if (cra == crb && n2) + m_operands = StringFromFormat("%d, %d", crd, cra); + else + m_operands = StringFromFormat("%d, %d, %d", crd, cra, crb); + } + else + { + ill(in); + } +} + + +void GekkoDisassembler::nooper(u32 in, const char* name, unsigned char dmode) +{ + if (in & (PPCDMASK | PPCAMASK | PPCBMASK | 1)) + { + ill(in); + } + else + { + m_flags |= dmode; + m_opcode = name; + } +} + +void GekkoDisassembler::rlw(u32 in, const char* name, int i) +{ + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)PPCGETB(in); + int mb = (int)PPCGETC(in); + int me = (int)PPCGETM(in); + + m_opcode = StringFromFormat("rlw%s%c", name, in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %s%d, %d, %d (%08x)", regnames[a], regnames[s], regsel[i], bsh, mb, me, HelperRotateMask(bsh, mb, me)); +} + + +void GekkoDisassembler::ori(u32 in, const char* name) +{ + m_opcode = name; + m_operands = imm(in, 1, 1, true); +} + + +void GekkoDisassembler::rld(u32 in, const char* name, int i) +{ + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = i ? (int)PPCGETB(in) : (int)(((in & 2) << 4) + PPCGETB(in)); + int m = (int)(in & 0x7e0) >> 5; + + m_flags |= PPCF_64; + m_opcode = StringFromFormat("rld%s%c", name, in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %s%d, %d", regnames[a], regnames[s], regsel[i], bsh, m); +} + + +void GekkoDisassembler::cmp(u32 in) +{ + int i = (int)PPCGETL(in); + + if (i < 2) + { + if (i != 0) + m_flags |= PPCF_64; + + m_opcode = cmpname[((in&PPCIDX2MASK) ? 2 : 0) + i]; + + i = (int)PPCGETCRD(in); + if (i != 0) + m_operands += StringFromFormat("cr%c,", '0' + i); + + m_operands += ra_rb(in); + } + else + { + ill(in); + } +} + + +void GekkoDisassembler::trap(u32 in, unsigned char dmode) +{ + int to = (int)PPCGETD(in); + const char* cnd = trap_condition[to]; + + if (cnd != nullptr) + { + m_flags |= dmode; + m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); + m_operands = ra_rb(in); + } + else + { + if (to == 31) + { + if (dmode) + { + m_flags |= dmode; + m_opcode = "td"; + m_operands = "31,0,0"; + } + else + { + m_opcode = "trap"; + } + } + else + { + ill(in); + } + } +} + +// Standard instruction: xxxx rD,rA,rB +void GekkoDisassembler::dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode) +{ + if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) + { + ill(in); + } + else + { + m_flags |= dmode; + + // rA,rS,rB + if (smode) + in = swapda(in); + + m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]); + m_operands = rd_ra_rb(in, mask); + } +} + +// Last operand is no register: xxxx rD,rA,NB +void GekkoDisassembler::rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode) +{ + if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) + { + ill(in); + } + else + { + m_flags |= dmode; + + // rA,rS,NB + if (smode) + in = swapda(in); + + m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]); + + m_operands = rd_ra_rb(in, 6); + m_operands += StringFromFormat(",%d",(int)PPCGETB(in)); + } +} + + +void GekkoDisassembler::mtcr(u32 in) +{ + int s = (int)PPCGETD(in); + int crm = (int)(in & 0x000ff000) >> 12; + + if (in & 0x00100801) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("mtcr%c", crm == 0xff ? '\0' : 'f'); + + if (crm != 0xff) + m_operands += StringFromFormat("0x%02x,", crm); + + m_operands += regnames[s]; + } +} + + +void GekkoDisassembler::msr(u32 in, int smode) +{ + int s = (int)PPCGETD(in); + int sr = (int)(in & 0x000f0000) >> 16; + + if (in & 0x0010f801) + { + ill(in); + } + else + { + m_flags |= PPCF_SUPER; + m_opcode = StringFromFormat("m%csr", smode ? 't' : 'f'); + + if (smode) + m_operands = StringFromFormat("%d, %s", sr, regnames[s]); + else + m_operands = StringFromFormat("%s, %d", regnames[s], sr); + } +} + + +void GekkoDisassembler::mspr(u32 in, int smode) +{ + int d = (int)PPCGETD(in); + int spr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); + int fmt = 0; + + if (in & 1) + { + ill(in); + } + else + { + if (spr != 1 && spr != 8 && spr != 9) + m_flags |= PPCF_SUPER; + + const char* x; + switch (spr) + { + case 1: + x = "xer"; + break; + + case 8: + x = "lr"; + break; + + case 9: + x = "ctr"; + break; + + default: + x = "spr"; + fmt = 1; + break; + } + + m_opcode = StringFromFormat("m%c%s", smode ? 't' : 'f', x); + + if (fmt) + { + if (smode) + m_operands = StringFromFormat("%s, %s", spr_name(spr).c_str(), regnames[d]); + else + m_operands = StringFromFormat("%s, %s", regnames[d], spr_name(spr).c_str()); + } + else + { + m_operands = regnames[d]; + } + } +} + + +void GekkoDisassembler::mtb(u32 in) +{ + int d = (int)PPCGETD(in); + int tbr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); + + if (in & 1) + { + ill(in); + } + else + { + m_operands += regnames[d]; + + char x; + switch (tbr) + { + case 268: + x = 'l'; + break; + + case 269: + x = 'u'; + break; + + default: + x = '\0'; + m_flags |= PPCF_SUPER; + m_operands += StringFromFormat(",%d", tbr); + break; + } + + m_opcode = StringFromFormat("mftb%c", x); + } +} + + +void GekkoDisassembler::sradi(u32 in) +{ + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)(((in & 2) << 4) + PPCGETB(in)); + + m_flags |= PPCF_64; + m_opcode = StringFromFormat("sradi%c", in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %d", regnames[a], regnames[s], bsh); +} + +void GekkoDisassembler::ldst(u32 in, const char* name, char reg, unsigned char dmode) +{ + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int d = (u32)(in & 0xffff); + + m_type = PPCINSTR_LDST; + m_flags |= dmode; + m_sreg = (short)a; + // if (d >= 0x8000) + // d -= 0x10000; + m_displacement = (u32)d; + m_opcode = name; + + if (reg == 'r') + { + m_operands = StringFromFormat("%s, %s (%s)", regnames[s], ldst_offs(d).c_str(), regnames[a]); + } + else + { + m_operands = StringFromFormat("%c%d, %s (%s)", reg, s, ldst_offs(d).c_str(), regnames[a]); + } +} + +// Standard floating point instruction: xxxx fD,fA,fC,fB +void GekkoDisassembler::fdabc(u32 in, const char* name, int mask, unsigned char dmode) +{ + int err = 0; + + m_flags |= dmode; + m_opcode = StringFromFormat("f%s%s", name, rcsel[in & 1]); + m_operands += StringFromFormat("f%d,", (int)PPCGETD(in)); + + if (mask & 4) + m_operands += StringFromFormat("f%d,", (int)PPCGETA(in)); + else + err |= (int)PPCGETA(in); + + if (mask & 2) + m_operands += StringFromFormat("f%d,", (int)PPCGETC(in)); + else if (PPCGETC(in)) + err |= (int)PPCGETC(in); + + if (mask & 1) + m_operands += StringFromFormat("f%d,", (int)PPCGETB(in)); + else if (!(mask & 8)) + err |= (int)PPCGETB(in); + + // Drop the trailing comma + m_operands.pop_back(); + + if (err) + ill(in); +} + +void GekkoDisassembler::fmr(u32 in) +{ + m_opcode = StringFromFormat("fmr%s", rcsel[in & 1]); + m_operands = StringFromFormat("f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in)); +} + +// Indexed float instruction: xxxx fD,rA,rB +void GekkoDisassembler::fdab(u32 in, const char* name, int mask) +{ + m_opcode = name; + m_operands = fd_ra_rb(in, mask); +} + + +void GekkoDisassembler::fcmp(u32 in, char c) +{ + if (in & 0x00600001) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("fcmp%c", c); + m_operands = StringFromFormat("cr%d,f%d,f%d", (int)PPCGETCRD(in), (int)PPCGETA(in), (int)PPCGETB(in)); + } +} + + +void GekkoDisassembler::mtfsb(u32 in, int n) +{ + if (in & (PPCAMASK | PPCBMASK)) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("mtfsb%d%s", n, rcsel[in & 1]); + m_operands = StringFromFormat("%d", (int)PPCGETD(in)); + } +} + + +// Paired instructions + +#define RA ((inst >> 16) & 0x1f) +#define RB ((inst >> 11) & 0x1f) +#define RC ((inst >> 6) & 0x1f) +#define RD ((inst >> 21) & 0x1f) +#define RS ((inst >> 21) & 0x1f) +#define FA ((inst >> 16) & 0x1f) +#define FB ((inst >> 11) & 0x1f) +#define FC ((inst >> 6) & 0x1f) +#define FD ((inst >> 21) & 0x1f) +#define FS ((inst >> 21) & 0x1f) +#define IMM (inst & 0xffff) +#define UIMM (inst & 0xffff) +#define OFS (inst & 0xffff) +#define OPCD ((inst >> 26) & 0x3f) +#define XO_10 ((inst >> 1) & 0x3ff) +#define XO_9 ((inst >> 1) & 0x1ff) +#define XO_5 ((inst >> 1) & 0x1f) +#define Rc (inst & 1) +#define SH ((inst >> 11) & 0x1f) +#define MB ((inst >> 6) & 0x1f) +#define ME ((inst >> 1) & 0x1f) +#define OE ((inst >> 10) & 1) +#define TO ((inst >> 21) & 0x1f) +#define CRFD ((inst >> 23) & 0x7) +#define CRFS ((inst >> 18) & 0x7) +#define CRBD ((inst >> 21) & 0x1f) +#define CRBA ((inst >> 16) & 0x1f) +#define CRBB ((inst >> 11) & 0x1f) +#define L ((inst >> 21) & 1) +#define NB ((inst >> 11) & 0x1f) +#define AA ((inst >> 1) & 1) +#define LK (inst & 1) +#define LI ((inst >> 2) & 0xffffff) +#define BO ((inst >> 21) & 0x1f) +#define BI ((inst >> 16) & 0x1f) +#define BD ((inst >> 2) & 0x3fff) + +#define MTFSFI_IMM ((inst >> 12) & 0xf) +#define FM ((inst >> 17) & 0xff) +#define SR ((inst >> 16) & 0xf) +#define SPR ((inst >> 11) & 0x3ff) +#define TBR ((inst >> 11) & 0x3ff) +#define CRM ((inst >> 12) & 0xff) + + +void GekkoDisassembler::ps(u32 inst) +{ + switch ((inst >> 1) & 0x1F) + { + case 6: + m_opcode = "ps_lux"; + m_operands = StringFromFormat("p%u, (r%u + r%u)", FD, RA, RB); + return; + + case 18: + m_opcode = "ps_div"; + m_operands = StringFromFormat("p%u, p%u/p%u", FD, FA, FB); + return; + + case 20: + m_opcode = "ps_sub"; + m_operands = StringFromFormat("p%u, p%u-p%u", FD, FA, FB); + return; + + case 21: + m_opcode = "ps_add"; + m_operands = StringFromFormat("p%u, p%u+p%u", FD, FA, FB); + return; + + case 23: + m_opcode = "ps_sel"; + m_operands = StringFromFormat("p%u>=0?p%u:p%u", FD, FA, FC); + return; + + case 24: + m_opcode = "ps_res"; + m_operands = StringFromFormat("p%u, (1/p%u)", FD, FB); + return; + + case 25: + m_opcode = "ps_mul"; + m_operands = StringFromFormat("p%u, p%u*p%u", FD, FA, FC); + return; + + case 26: // rsqrte + m_opcode = "ps_rsqrte"; + m_operands = StringFromFormat("p%u, p%u", FD, FB); + return; + + case 28: // msub + m_opcode = "ps_msub"; + m_operands = StringFromFormat("p%u, p%u*p%u-p%u", FD, FA, FC, FB); + return; + + case 29: // madd + m_opcode = "ps_madd"; + m_operands = StringFromFormat("p%u, p%u*p%u+p%u", FD, FA, FC, FB); + return; + + case 30: // nmsub + m_opcode = "ps_nmsub"; + m_operands = StringFromFormat("p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); + return; + + case 31: // nmadd + m_opcode = "ps_nmadd"; + m_operands = StringFromFormat("p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); + return; + + case 10: + m_opcode = "ps_sum0"; + m_operands = StringFromFormat("p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); + return; + + case 11: + m_opcode = "ps_sum1"; + m_operands = StringFromFormat("p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); + return; + + case 12: + m_opcode = "ps_muls0"; + m_operands = StringFromFormat("p%u, p%u*p%u[0]", FD, FA, FC); + return; + + case 13: + m_opcode = "ps_muls1"; + m_operands = StringFromFormat("p%u, p%u*p%u[1]", FD, FA, FC); + return; + + case 14: + m_opcode = "ps_madds0"; + m_operands = StringFromFormat("p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); + return; + + case 15: + m_opcode = "ps_madds1"; + m_operands = StringFromFormat("p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); + return; + } + + switch ((inst >> 1) & 0x3FF) + { + // 10-bit suckers (?) + case 40: // nmadd + m_opcode = "ps_neg"; + m_operands = StringFromFormat("p%u, -p%u", FD, FB); + return; + + case 72: // nmadd + m_opcode = "ps_mr"; + m_operands = StringFromFormat("p%u, p%u", FD, FB); + return; + + case 136: + m_opcode = "ps_nabs"; + m_operands = StringFromFormat("p%u, -|p%u|", FD, FB); + return; + + case 264: + m_opcode = "ps_abs"; + m_operands = StringFromFormat("p%u, |p%u|", FD, FB); + return; + + case 0: + m_opcode = "ps_cmpu0"; + m_operands = "ps_cmpu0"; + return; + + case 32: + m_opcode = "ps_cmpq0"; + m_operands = "ps_cmpo0"; + return; + + case 64: + m_opcode = "ps_cmpu1"; + m_operands = "ps_cmpu1"; + return; + + case 96: + m_opcode = "ps_cmpo1"; + m_operands = "ps_cmpo1"; + return; + + case 528: + m_opcode = "ps_merge00"; + m_operands = StringFromFormat("p%u, p%u[0],p%u[0]", FD, FA, FB); + return; + + case 560: + m_opcode = "ps_merge01"; + m_operands = StringFromFormat("p%u, p%u[0],p%u[1]", FD, FA, FB); + return; + + case 592: + m_opcode = "ps_merge10"; + m_operands = StringFromFormat("p%u, p%u[1],p%u[0]", FD, FA, FB); + return; + + case 624: + m_opcode = "ps_merge11"; + m_operands = StringFromFormat("p%u, p%u[1],p%u[1]", FD, FA, FB); + return; + + case 1014: + m_opcode = "dcbz_l"; + m_operands = ""; + return; + } + + // default: + m_opcode = StringFromFormat("ps_%i", ((inst >> 1) & 0x1f)); + m_operands = "---"; +} + +void GekkoDisassembler::ps_mem(u32 inst) +{ + switch (PPCGETIDX(inst)) + { + case 56: + m_opcode = "psq_l"; + m_operands = StringFromFormat("p%u, %i(r%u)", RS, SEX12(inst & 0xFFF), RA); + break; + + case 57: + m_opcode = "psq_lu"; + m_operands = ""; + break; + + case 60: + m_opcode = "psq_st"; + m_operands = StringFromFormat("%i(r%u), p%u", SEX12(inst & 0xFFF), RA, RS); + break; + + case 61: + m_opcode = "psq_stu"; + m_operands = StringFromFormat("r%u, p%u ?", RA, RS); + break; + } +} + +// Disassemble PPC instruction and return a pointer to the next +// instruction, or nullptr if an error occured. +u32* GekkoDisassembler::DoDisassembly(bool big_endian) +{ + u32 in = *m_instr; + + if (!big_endian) + { + in = (in & 0xff) << 24 | (in & 0xff00) << 8 | (in & 0xff0000) >> 8 | + (in & 0xff000000) >> 24; + } + + m_opcode.clear(); + m_operands.clear(); + m_type = PPCINSTR_OTHER; + m_flags = 0; + + switch (PPCGETIDX(in)) + { + case 0: + { + int block = in & 0x3FFFFFF; + if (block) + { + m_opcode = "JITblock"; + m_operands = StringFromFormat("%i", block); + } + else + { + m_opcode = ""; + m_operands = "---"; + } + } + break; + + case 1: // HLE call + m_opcode = "HLE"; + break; + + case 2: + trapi(in, PPCF_64); // tdi + break; + + case 3: + trapi(in, 0); // twi + break; + + case 4: + ps(in); + break; + + case 56: + case 57: + case 60: + case 61: + ps_mem(in); + break; + + case 7: + m_opcode = "mulli"; + m_operands = imm(in, 0, 0, false); + break; + + case 8: + m_opcode = "subfic"; + m_operands = imm(in, 0, 0, false); + break; + + case 10: + cmpi(in, 1); // cmpli + break; + + case 11: + cmpi(in, 0); // cmpi + break; + + case 12: + addi(in, "ic"); // addic + break; + + case 13: + addi(in, "ic."); // addic. + break; + + case 14: + addi(in, "i"); // addi + break; + + case 15: + addi(in, "is"); // addis + break; + + case 16: + bc(in); + break; + + case 17: + if ((in & ~PPCIDXMASK) == 2) + m_opcode = "sc"; + else + ill(in); + break; + + case 18: + bli(in); + break; + + case 19: + switch (PPCGETIDX2(in)) + { + case 0: + mcrf(in, '\0'); // mcrf + break; + + case 16: + branch(in, "lr", 0, 0); // bclr + break; + + case 33: + crop(in, "nor", "not"); // crnor + break; + + case 50: + nooper(in, "rfi", PPCF_SUPER); + break; + + case 129: + crop(in, "andc", nullptr); // crandc + break; + + case 150: + nooper(in, "isync", 0); + break; + + case 193: + crop(in, "xor", "clr"); // crxor + break; + + case 225: + crop(in, "nand", nullptr); // crnand + break; + + case 257: + crop(in, "and", nullptr); // crand + break; + + case 289: + crop(in, "eqv", "set"); // creqv + break; + + case 417: + crop(in, "orc", nullptr); // crorc + break; + + case 449: + crop(in, "or", "move"); // cror + break; + + case 528: + branch(in, "ctr", 0, 0); // bcctr + break; + + default: + ill(in); + break; + } + break; + + case 20: + rlw(in, "imi", 0); // rlwimi + break; + + case 21: + rlw(in, "inm", 0); // rlwinm + break; + + case 23: + rlw(in, "nm", 1); // rlwnm + break; + + case 24: + if (in & ~PPCIDXMASK) + ori(in, "ori"); + else + m_opcode = "nop"; + break; + + case 25: + ori(in, "oris"); + break; + + case 26: + ori(in, "xori"); + break; + + case 27: + ori(in, "xoris"); + break; + + case 28: + ori(in, "andi."); + break; + + case 29: + ori(in, "andis."); + break; + + case 30: + switch (in & 0x1c) + { + case 0: + rld(in, "icl", 0); // rldicl + break; + case 1: + rld(in, "icr", 0); // rldicr + break; + case 2: + rld(in, "ic", 0); // rldic + break; + case 3: + rld(in, "imi", 0); // rldimi + break; + case 4: + rld(in, in & 2 ? "cl" : "cr", 1); // rldcl, rldcr + break; + default: + ill(in); + break; + } + break; + + case 31: + switch (PPCGETIDX2(in)) + { + case 0: + case 32: + if (in & 1) + ill(in); + else + cmp(in); // cmp, cmpl + break; + + case 4: + if (in & 1) + ill(in); + else + trap(in, 0); // tw + break; + + case 8: + case (PPCOE >> 1) + 8: + dab(swapab(in), "subc", 7, 0, 1, -1, 0); + break; + + case 9: + dab(in, "mulhdu", 7, 0, 0, -1, PPCF_64); + break; + + case 10: + case (PPCOE >> 1) + 10: + dab(in, "addc", 7, 0, 1, -1, 0); + break; + + case 11: + dab(in, "mulhwu", 7, 0, 0, -1, 0); + break; + + case 19: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mfcr", 4, 0, 0, 0, 0); + break; + + case 20: + dab(in, "lwarx", 7, 0, 0, 0, 0); + break; + + case 21: + dab(in, "ldx", 7, 0, 0, 0, PPCF_64); + break; + + case 23: + dab(in, "lwzx", 7, 0, 0, 0, 0); + break; + + case 24: + dab(in, "slw", 7, 1, 0, -1, 0); + break; + + case 26: + if (in & PPCBMASK) + ill(in); + else + dab(in, "cntlzw", 6, 1, 0, -1, 0); + break; + + case 27: + dab(in, "sld", 7, 1, 0, -1, PPCF_64); + break; + + case 28: + dab(in, "and", 7, 1, 0, -1, 0); + break; + + case 40: + case (PPCOE >> 1) + 40: + dab(swapab(in), "sub", 7, 0, 1, -1, 0); + break; + + case 53: + dab(in, "ldux", 7, 0, 0, 0, PPCF_64); + break; + + case 54: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbst", 3, 0, 0, 0, 0); + break; + + case 55: + dab(in, "lwzux", 7, 0, 0, 0, 0); + break; + + case 58: + if (in & PPCBMASK) + ill(in); + else + dab(in, "cntlzd", 6, 1, 0, -1, PPCF_64); + break; + + case 60: + dab(in, "andc", 7, 1, 0, -1, 0); + break; + + case 68: + trap(in, PPCF_64); // td + break; + + case 73: + dab(in, "mulhd", 7, 0, 0, -1, PPCF_64); + break; + + case 75: + dab(in, "mulhw", 7, 0, 0, -1, 0); + break; + + case 83: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mfmsr", 4, 0, 0, 0, PPCF_SUPER); + break; + + case 84: + dab(in, "ldarx", 7, 0, 0, 0, PPCF_64); + break; + + case 86: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbf", 3, 0, 0, 0, 0); + break; + + case 87: + dab(in, "lbzx", 7, 0, 0, 0, 0); + break; + + case 104: + case (PPCOE >> 1) + 104: + if (in & PPCBMASK) + ill(in); + else + dab(in, "neg", 6, 0, 1, -1, 0); + break; + + case 119: + dab(in, "lbzux", 7, 0, 0, 0, 0); + break; + + case 124: + if (PPCGETD(in) == PPCGETB(in)) + dab(in, "not", 6, 1, 0, -1, 0); + else + dab(in, "nor", 7, 1, 0, -1, 0); + break; + + case 136: + case (PPCOE >> 1) + 136: + dab(in, "subfe", 7, 0, 1, -1, 0); + break; + + case 138: + case (PPCOE >> 1) + 138: + dab(in, "adde", 7, 0, 1, -1, 0); + break; + + case 144: + mtcr(in); + break; + + case 146: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mtmsr", 4, 0, 0, 0, PPCF_SUPER); + break; + + case 149: + dab(in, "stdx", 7, 0, 0, 0, PPCF_64); + break; + + case 150: + dab(in, "stwcx.", 7, 0, 0, 1, 0); + break; + + case 151: + dab(in, "stwx", 7, 0, 0, 0, 0); + break; + + case 181: + dab(in, "stdux", 7, 0, 0, 0, PPCF_64); + break; + + case 183: + dab(in, "stwux", 7, 0, 0, 0, 0); + break; + + case 200: + case (PPCOE >> 1) + 200: + if (in & PPCBMASK) + ill(in); + else + dab(in, "subfze", 6, 0, 1, -1, 0); + break; + + case 202: + case (PPCOE >> 1) + 202: + if (in & PPCBMASK) + ill(in); + else + dab(in, "addze", 6, 0, 1, -1, 0); + break; + + case 210: + msr(in, 1); // mfsr + break; + + case 214: + dab(in, "stdcx.", 7, 0, 0, 1, PPCF_64); + break; + + case 215: + dab(in, "stbx", 7, 0, 0, 0, 0); + break; + + case 232: + case (PPCOE >> 1) + 232: + if (in & PPCBMASK) + ill(in); + else + dab(in, "subfme", 6, 0, 1, -1, 0); + break; + + case 233: + case (PPCOE >> 1) + 233: + dab(in, "mulld", 7, 0, 1, -1, PPCF_64); + break; + + case 234: + case (PPCOE >> 1) + 234: + if (in & PPCBMASK) + ill(in); + else + dab(in, "addme", 6, 0, 1, -1, 0); + break; + + case 235: + case (PPCOE >> 1) + 235: + dab(in, "mullw", 7, 0, 1, -1, 0); + break; + + case 242: + if (in & PPCAMASK) + ill(in); + else + dab(in, "mtsrin", 5, 0, 0, 0, PPCF_SUPER); + break; + + case 246: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbtst", 3, 0, 0, 0, 0); + break; + + case 247: + dab(in, "stbux", 7, 0, 0, 0, 0); + break; + + case 266: + case (PPCOE >> 1) + 266: + dab(in, "add", 7, 0, 1, -1, 0); + break; + + case 278: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbt", 3, 0, 0, 0, 0); + break; + + case 279: + dab(in, "lhzx", 7, 0, 0, 0, 0); + break; + + case 284: + dab(in, "eqv", 7, 1, 0, -1, 0); + break; + + case 306: + if (in & (PPCDMASK | PPCAMASK)) + ill(in); + else + dab(in, "tlbie", 1, 0, 0, 0, PPCF_SUPER); + break; + + case 310: + dab(in, "eciwx", 7, 0, 0, 0, 0); + break; + + case 311: + dab(in, "lhzux", 7, 0, 0, 0, 0); + break; + + case 316: + dab(in, "xor", 7, 1, 0, -1, 0); + break; + + case 339: + mspr(in, 0); // mfspr + break; + + case 341: + dab(in, "lwax", 7, 0, 0, 0, PPCF_64); + break; + + case 343: + dab(in, "lhax", 7, 0, 0, 0, 0); + break; + + case 370: + nooper(in, "tlbia", PPCF_SUPER); + break; + + case 371: + mtb(in); // mftb + break; + + case 373: + dab(in, "lwaux", 7, 0, 0, 0, PPCF_64); + break; + + case 375: + dab(in, "lhaux", 7, 0, 0, 0, 0); + break; + + case 407: + dab(in, "sthx", 7, 0, 0, 0, 0); + break; + + case 412: + dab(in, "orc", 7, 1, 0, -1, 0); + break; + + case 413: + sradi(in); // sradi + break; + + case 434: + if (in & (PPCDMASK | PPCAMASK)) + ill(in); + else + dab(in, "slbie", 1, 0, 0, 0, PPCF_SUPER | PPCF_64); + break; + + case 438: + dab(in, "ecowx", 7, 0, 0, 0, 0); + break; + + case 439: + dab(in, "sthux", 7, 0, 0, 0, 0); + break; + + case 444: + if (PPCGETD(in) == PPCGETB(in)) + dab(in, "mr", 6, 1, 0, -1, 0); + else + dab(in, "or", 7, 1, 0, -1, 0); + break; + + case 457: + case (PPCOE >> 1) + 457: + dab(in, "divdu", 7, 0, 1, -1, PPCF_64); + break; + + case 459: + case (PPCOE >> 1) + 459: + dab(in, "divwu", 7, 0, 1, -1, 0); + break; + + case 467: + mspr(in, 1); // mtspr + break; + + case 470: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbi", 3, 0, 0, 0, 0); + break; + + case 476: + dab(in, "nand", 7, 1, 0, -1, 0); + break; + + case 489: + case (PPCOE >> 1) + 489: + dab(in, "divd", 7, 0, 1, -1, PPCF_64); + break; + + case 491: + case (PPCOE >> 1) + 491: + dab(in, "divw", 7, 0, 1, -1, 0); + break; + + case 498: + nooper(in, "slbia", PPCF_SUPER | PPCF_64); + break; + + case 512: + if (in & 0x007ff801) + { + ill(in); + } + else + { + m_opcode = "mcrxr"; + m_operands = StringFromFormat("cr%d", (int)PPCGETCRD(in)); + } + break; + + case 533: + dab(in, "lswx", 7, 0, 0, 0, 0); + break; + + case 534: + dab(in, "lwbrx", 7, 0, 0, 0, 0); + break; + + case 535: + fdab(in, "lfsx", 7); + break; + + case 536: + dab(in, "srw", 7, 1, 0, -1, 0); + break; + + case 539: + dab(in, "srd", 7, 1, 0, -1, PPCF_64); + break; + + case 566: + nooper(in, "tlbsync", PPCF_SUPER); + break; + + case 567: + fdab(in, "lfsux", 7); + break; + + case 595: + msr(in, 0); // mfsr + break; + + case 597: + rrn(in, "lswi", 0, 0, 0, 0); + break; + + case 598: + nooper(in, "sync", PPCF_SUPER); + break; + + case 599: + fdab(in, "lfdx", 7); + break; + + case 631: + fdab(in, "lfdux", 7); + break; + + case 659: + if (in & PPCAMASK) + ill(in); + else + dab(in, "mfsrin", 5, 0, 0, 0, PPCF_SUPER); + break; + + case 661: + dab(in, "stswx", 7, 0, 0, 0, 0); + break; + + case 662: + dab(in, "stwbrx", 7, 0, 0, 0, 0); + break; + + case 663: + fdab(in, "stfsx", 7); + break; + + case 695: + fdab(in, "stfsux", 7); + break; + + case 725: + rrn(in, "stswi", 0, 0, 0, 0); + break; + + case 727: + fdab(in, "stfdx", 7); + break; + + case 759: + fdab(in, "stfdux", 7); + break; + + case 790: + dab(in, "lhbrx", 7, 0, 0, 0, 0); + break; + + case 792: + dab(in, "sraw", 7, 1, 0, -1, 0); + break; + + case 794: + dab(in, "srad", 7, 1, 0, -1, PPCF_64); + break; + + case 824: + rrn(in, "srawi", 1, 0, -1, 0); + break; + + case 854: + nooper(in, "eieio", PPCF_SUPER); + break; + + case 918: + dab(in, "sthbrx", 7, 0, 0, 0, 0); + break; + + case 922: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsh", 6, 1, 0, -1, 0); + break; + + case 954: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsb", 6, 1, 0, -1, 0); + break; + + case 982: + if (in & PPCDMASK) + ill(in); + else + dab(in, "icbi", 3, 0, 0, 0, 0); + break; + + case 983: + fdab(in, "stfiwx", 7); + break; + + case 986: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsw", 6, 1, 0, -1, PPCF_64); + break; + + case 1014: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbz", 3, 0, 0, 0, 0); + break; + + default: + ill(in); + break; + } + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + ldst(in, ldstnames[PPCGETIDX(in) - 32], 'r', 0); + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + ldst(in, ldstnames[PPCGETIDX(in) - 32], 'f', 0); + break; + + case 58: + switch (in & 3) + { + case 0: + ldst(in&~3, "ld", 'r', PPCF_64); + break; + case 1: + ldst(in&~3, "ldu", 'r', PPCF_64); + break; + case 2: + ldst(in&~3, "lwa", 'r', PPCF_64); + break; + default: + ill(in); + break; + } + break; + + case 59: + switch (in & 0x3e) + { + case 36: + fdabc(in, "divs", 5, 0); + break; + + case 40: + fdabc(in, "subs", 5, 0); + break; + + case 42: + fdabc(in, "adds", 5, 0); + break; + + case 44: + fdabc(in, "sqrts", 2, 0); + break; + + case 48: + fdabc(in, "res", 2, 0); + break; + + case 50: + fdabc(in, "muls", 6, 0); + break; + + case 56: + fdabc(in, "msubs", 7, 0); + break; + + case 58: + fdabc(in, "madds", 7, 0); + break; + + case 60: + fdabc(in, "nmsubs", 7, 0); + break; + + case 62: + fdabc(in, "nmadds", 7, 0); + break; + + default: + ill(in); + break; + } + break; + + case 62: + switch (in & 3) + { + case 0: + ldst(in&~3, "std", 'r', PPCF_64); + break; + case 1: + ldst(in&~3, "stdu", 'r', PPCF_64); + break; + default: + ill(in); + break; + } + break; + + case 63: + if (in & 32) + { + switch (in & 0x1e) + { + case 4: + fdabc(in, "div", 5, 0); + break; + + case 8: + fdabc(in, "sub", 5, 0); + break; + + case 10: + fdabc(in, "add", 5, 0); + break; + + case 12: + fdabc(in, "sqrt", 2, 0); + break; + + case 14: + fdabc(in, "sel", 7, 0); + break; + + case 18: + fdabc(in, "mul", 6, 0); + break; + + case 20: + fdabc(in, "rsqrte", 1, 0); + break; + + case 24: + fdabc(in, "msub", 7, 0); + break; + + case 26: + fdabc(in, "madd", 7, 0); + break; + + case 28: + fdabc(in, "nmsub", 7, 0); + break; + + case 30: + fdabc(in, "nmadd", 7, 0); + break; + + case 52: + m_opcode = "XXX dp 52"; + break; + + default: + ill(in); + break; + } + } + else + { + switch (PPCGETIDX2(in)) + { + case 0: + fcmp(in, 'u'); + break; + + case 12: + fdabc(in, "rsp", 1, 0); + break; + + case 14: + fdabc(in, "ctiw", 1, 0); + break; + + case 15: + fdabc(in, "ctiwz", 1, 0); + break; + + case 32: + fcmp(in, 'o'); + break; + + case 38: + mtfsb(in, 1); + break; + + case 40: + fdabc(in, "neg", 10, 0); + break; + + case 64: + mcrf(in, 's'); // mcrfs + break; + + case 70: + mtfsb(in, 0); + break; + + case 72: + fmr(in); + break; + + case 134: + if ((in & 0x006f0800) == 0) + { + m_opcode = StringFromFormat("mtfsfi%s", rcsel[in & 1]); + m_operands = StringFromFormat("cr%d,%d", (int)PPCGETCRD(in), (int)(in & 0xf000) >> 12); + } + else + { + ill(in); + } + break; + + case 136: + fdabc(in, "nabs", 10, 0); + break; + + case 264: + fdabc(in, "abs", 10, 0); + break; + + case 583: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mffs", 4, 0, 0, -1, 0); + break; + + case 711: + if ((in & 0x02010000) == 0) + { + m_opcode = StringFromFormat("mtfsf%s", rcsel[in & 1]); + m_operands = StringFromFormat("0x%x,%u", (unsigned int)(in & 0x01fe) >> 17, (int)PPCGETB(in)); + } + else + { + ill(in); + } + break; + + case 814: + fdabc(in, "fctid", 10, PPCF_64); + break; + + case 815: + fdabc(in, "fctidz", 10, PPCF_64); + break; + + case 846: + fdabc(in, "fcfid", 10, PPCF_64); + break; + + default: + ill(in); + break; + } + } + break; + + default: + ill(in); + break; + } + return (m_instr + 1); +} + +// simplified interface +std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian) +{ + u32 opc = opcode; + u32 addr = current_instruction_address; + + m_instr = (u32*)&opc; + m_iaddr = (u32*)&addr; + + DoDisassembly(big_endian); + + return m_opcode.append("\t").append(m_operands); +} + +static const char* gprnames[] = +{ + " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7", + " r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +const char* GekkoDisassembler::GetGPRName(u32 index) +{ + if (index < 32) + return gprnames[index]; + + return 0; +} + +static const char* fprnames[] = +{ + " f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7", + " f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" +}; + +const char* GekkoDisassembler::GetFPRName(u32 index) +{ + if (index < 32) + return fprnames[index]; + + return 0; +} diff --git a/Source/Core/Common/GekkoDisassembler.h b/Source/Core/Common/GekkoDisassembler.h new file mode 100644 index 0000000000..113c843baa --- /dev/null +++ b/Source/Core/Common/GekkoDisassembler.h @@ -0,0 +1,152 @@ +/* $VER: ppc_disasm.h V1.6 (09.12.2011) + * + * Disassembler module for the PowerPC microprocessor family + * Copyright (c) 1998-2001,2009,2011 Frank Wille + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +// Modified for use with Dolphin + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/StringUtil.h" + +class GekkoDisassembler final +{ +public: + static std::string Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian = true); + static const char* GetGPRName(u32 index); + static const char* GetFPRName(u32 index); + +private: + GekkoDisassembler() = delete; + + static void ill(u32 in); + static std::string imm(u32 in, int uimm, int type, bool hex); + + static std::string ra_rb(u32 in); + static std::string rd_ra_rb(u32 in, int mask); + static std::string fd_ra_rb(u32 in, int mask); + + static void trapi(u32 in, unsigned char dmode); + static void cmpi(u32 in, int uimm); + static void addi(u32 in, const std::string& ext); + static size_t branch(u32 in, const char* bname, int aform, int bdisp); + static void bc(u32 in); + static void bli(u32 in); + static void mcrf(u32 in, char c); + static void crop(u32 in, const char* n1, const char* n2); + static void nooper(u32 in, const char* name, unsigned char dmode); + static void rlw(u32 in, const char* name, int i); + static void ori(u32 in, const char* name); + static void rld(u32 in, const char* name, int i); + static void cmp(u32 in); + static void trap(u32 in, unsigned char dmode); + static void dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode); + static void rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode); + static void mtcr(u32 in); + static void msr(u32 in, int smode); + static void mspr(u32 in, int smode); + static void mtb(u32 in); + static void sradi(u32 in); + static void ldst(u32 in, const char* name, char reg, unsigned char dmode); + static void fdabc(u32 in, const char* name, int mask, unsigned char dmode); + static void fmr(u32 in); + static void fdab(u32 in, const char* name, int mask); + static void fcmp(u32 in, char c); + static void mtfsb(u32 in, int n); + static void ps(u32 inst); + static void ps_mem(u32 inst); + + static u32* DoDisassembly(bool big_endian); + + static u32 HelperRotateMask(int r, int mb, int me) + { + //first make 001111111111111 part + unsigned int begin = 0xFFFFFFFF >> mb; + //then make 000000000001111 part, which is used to flip the bits of the first one + unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; + //do the bitflip + unsigned int mask = begin ^ end; + //and invert if backwards + if (me < mb) + mask = ~mask; + //rotate the mask so it can be applied to source reg + //return _rotl(mask, 32 - r); + return (mask << (32 - r)) | (mask >> r); + } + + static std::string ldst_offs(u32 val) + { + if (val == 0) + { + return "0"; + } + else + { + if (val & 0x8000) + { + return StringFromFormat("-0x%.4X", ((~val) & 0xffff) + 1); + } + else + { + return StringFromFormat("0x%.4X", val); + } + } + } + + static int SEX12(u32 x) + { + return x & 0x800 ? (x | 0xFFFFF000) : x; + } + + enum InstructionType + { + PPCINSTR_OTHER = 0, // No additional info for other instr. + PPCINSTR_BRANCH = 1, // Branch dest. = PC+displacement + PPCINSTR_LDST = 2, // Load/store instruction: displ(sreg) + PPCINSTR_IMM = 3, // 16-bit immediate val. in displacement + }; + + enum Flags + { + PPCF_ILLEGAL = (1 << 0), // Illegal PowerPC instruction + PPCF_UNSIGNED = (1 << 1), // Unsigned immediate instruction + PPCF_SUPER = (1 << 2), // Supervisor level instruction + PPCF_64 = (1 << 3), // 64-bit only instruction + }; + + static u32* m_instr; // Pointer to instruction to disassemble + static u32* m_iaddr; // Instruction.address., usually the same as instr + static std::string m_opcode; // Buffer for opcode, min. 10 chars. + static std::string m_operands; // Operand buffer, min. 24 chars. + static unsigned char m_type; // Type of instruction, see below + static unsigned char m_flags; // Additional flags + static unsigned short m_sreg; // Register in load/store instructions + static u32 m_displacement; // Branch- or load/store displacement +}; diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index d07d49c097..ed46e18db3 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "PowerPCDisasm.h" +#include + +#include "Common/GekkoDisassembler.h" #include "Core/Core.h" #include "Core/Host.h" @@ -15,31 +17,37 @@ #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/JitCommon/JitBase.h" -void PPCDebugInterface::Disassemble(unsigned int address, char *dest, int max_size) +std::string PPCDebugInterface::Disassemble(unsigned int address) { // Memory::ReadUnchecked_U32 seemed to crash on shutdown - if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) return; + if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) + return ""; if (Core::GetState() != Core::CORE_UNINITIALIZED) { if (Memory::IsRAMAddress(address, true, true)) { u32 op = Memory::Read_Instruction(address); - DisassembleGekko(op, address, dest, max_size); + std::string disasm = GekkoDisassembler::Disassemble(op, address); + UGeckoInstruction inst; inst.hex = Memory::ReadUnchecked_U32(address); - if (inst.OPCD == 1) { - strcat(dest, " (hle)"); + + if (inst.OPCD == 1) + { + disasm += " (hle)"; } + + return disasm; } else { - strcpy(dest, "(No RAM here)"); + return "(No RAM here)"; } } else { - strcpy(dest, ""); + return ""; } } diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index ba362694f1..c80416d58b 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -14,7 +14,7 @@ class PPCDebugInterface final : public DebugInterface { public: PPCDebugInterface(){} - virtual void Disassemble(unsigned int address, char *dest, int max_size) override; + virtual std::string Disassemble(unsigned int address) override; virtual void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override; virtual int GetInstructionSize(int /*instruction*/) override {return 4;} virtual bool IsAlive() override; diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp index 4520ddf80a..3ccd46a589 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp @@ -2,17 +2,18 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include + #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPDisassembler.h" #include "Core/DSP/DSPMemoryMap.h" #include "Core/HW/DSPLLE/DSPDebugInterface.h" #include "Core/HW/DSPLLE/DSPSymbols.h" -void DSPDebugInterface::Disassemble(unsigned int address, char *dest, int max_size) +std::string DSPDebugInterface::Disassemble(unsigned int address) { // we'll treat addresses as line numbers. - strncpy(dest, DSPSymbols::GetLineText(address), max_size); - dest[max_size-1] = 0; + return DSPSymbols::GetLineText(address); } void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h index f4a2494481..2342b940f0 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h @@ -5,7 +5,6 @@ #pragma once #include -#include #include "Common/Common.h" #include "Common/DebugInterface.h" @@ -14,7 +13,7 @@ class DSPDebugInterface final : public DebugInterface { public: DSPDebugInterface(){} - virtual void Disassemble(unsigned int address, char *dest, int max_size) override; + virtual std::string Disassemble(unsigned int address) override; virtual void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override; virtual int GetInstructionSize(int instruction) override { return 1; } virtual bool IsAlive() override; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index ff3bd8c4f8..070c369394 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -5,8 +5,7 @@ #include #include -#include "PowerPCDisasm.h" - +#include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/Host.h" #include "Core/Debugger/Debugger_SymbolMap.h" @@ -82,10 +81,8 @@ static void Trace(UGeckoInstruction& instCode) fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]); } - char ppcInst[256]; - DisassembleGekko(instCode.hex, PC, ppcInst, 256); - - DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppcInst); + std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC); + DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppc_inst.c_str()); } int Interpreter::SingleStepInner(void) @@ -312,9 +309,8 @@ void Interpreter::unknown_instruction(UGeckoInstruction _inst) { if (_inst.hex != 0) { - char disasm[256]; - DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256); - NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm); + std::string disasm = GekkoDisassembler::Disassemble(Memory::ReadUnchecked_U32(last_pc), last_pc); + NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str()); Dolphin_Debugger::PrintCallstack(); _dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 405d183a80..11a6e39b0c 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -21,7 +21,7 @@ #include "Core/PowerPC/Jit64/JitAsm.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #if defined(_DEBUG) || defined(DEBUGFAST) -#include "PowerPCDisasm.h" +#include "Common/GekkoDisassembler.h" #endif using namespace Gen; @@ -613,9 +613,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc #if defined(_DEBUG) || defined(DEBUGFAST) if (gpr.SanityCheck() || fpr.SanityCheck()) { - char ppcInst[256]; - DisassembleGekko(ops[i].inst.hex, em_address, ppcInst, 256); - //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppcInst); + std::string ppc_inst = GekkoDisassembler::Disassemble(ops[i].inst.hex, em_address); + //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); } #endif if (js.skipnext) { diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp index 440d507ace..097895ef85 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp @@ -6,8 +6,8 @@ #include #include "disasm.h" -#include "PowerPCDisasm.h" +#include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/PowerPC/JitCommon/JitBase.h" @@ -29,15 +29,11 @@ u32 Helper_Mask(u8 mb, u8 me) void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b) { - std::string ppcdisasm; - for (int i = 0; i < size; i++) { - char temp[256] = ""; const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[i]; - DisassembleGekko(op.inst.hex, op.address, temp, 256); - ppcdisasm += StringFromFormat("%08x %s", op.address, temp); - DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", ppcdisasm.c_str()); + std::string temp = StringFromFormat("%08x %s", op.address, GekkoDisassembler::Disassemble(op.inst.hex, op.address).c_str()); + DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", temp.c_str()); } disassembler x64disasm; diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 982b246f83..a63c586d97 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -334,9 +334,9 @@ bool PPCSymbolDB::SaveMap(const std::string& filename, bool WithCodes) const for (int i = 0; i < space; i += 4) { int Address = LastAddress + i; - char disasm[256]; - debugger->Disassemble(Address, disasm, 256); - fprintf(f.GetHandle(),"%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm); + + std::string disasm = debugger->Disassemble(Address); + fprintf(f.GetHandle(),"%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm.c_str()); } // Write a blank line after each block fprintf(f.GetHandle(), "\n"); diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp index 9d7b869518..7b18a5e9d8 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include #include #include #include @@ -189,15 +190,15 @@ void CCodeView::OnMouseUpL(wxMouseEvent& event) u32 CCodeView::AddrToBranch(u32 addr) { - char disasm[256]; - m_debugger->Disassemble(addr, disasm, 256); - const char *mojs = strstr(disasm, "->0x"); - if (mojs) + std::string disasm = m_debugger->Disassemble(addr); + size_t pos = disasm.find("->0x"); + + if (pos != std::string::npos) { - u32 dest; - sscanf(mojs+4,"%08x", &dest); - return dest; + std::string hex = disasm.substr(pos + 2); + return std::stoul(hex, nullptr, 16); } + return 0; } @@ -253,16 +254,14 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event) case IDM_COPYCODE: { - char disasm[256]; - m_debugger->Disassemble(m_selection, disasm, 256); + std::string disasm = m_debugger->Disassemble(m_selection); wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm))); } break; case IDM_COPYHEX: { - char temp[24]; - sprintf(temp, "%08x", m_debugger->ReadInstruction(m_selection)); + std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection)); wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp))); } break; @@ -280,9 +279,8 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event) u32 end = start + symbol->size; for (u32 addr = start; addr != end; addr += 4) { - char disasm[256]; - m_debugger->Disassemble(addr, disasm, 256); - text = text + StringFromFormat("%08x: ", addr) + disasm + "\r\n"; + std::string disasm = m_debugger->Disassemble(addr); + text += StringFromFormat("%08x: ", addr) + disasm + "\r\n"; } wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text))); } @@ -478,65 +476,51 @@ void CCodeView::OnPaint(wxPaintEvent& event) // If running if (m_debugger->IsAlive()) { - char dis[256]; - m_debugger->Disassemble(address, dis, 256); - char* dis2 = strchr(dis, '\t'); - char desc[256] = ""; + std::vector dis; + SplitString(m_debugger->Disassemble(address), '\t', dis); - // If we have a code - if (dis2) + static const size_t VALID_BRANCH_LENGTH = 10; + const std::string& opcode = dis[0]; + const std::string& operands = dis[1]; + std::string desc; + + // look for hex strings to decode branches + std::string hex_str; + size_t pos = operands.find("0x8"); + if (pos != std::string::npos) { - *dis2 = 0; - dis2++; - // look for hex strings to decode branches - const char* mojs = strstr(dis2, "0x8"); - if (mojs) - { - for (int k = 0; k < 8; k++) - { - bool found = false; - for (int j = 0; j < 22; j++) - { - if (mojs[k + 2] == "0123456789ABCDEFabcdef"[j]) - found = true; - } - if (!found) - { - mojs = nullptr; - break; - } - } - } - if (mojs) - { - int offs; - sscanf(mojs + 2, "%08x", &offs); - branches[numBranches].src = rowY1 + m_rowHeight / 2; - branches[numBranches].srcAddr = address / m_align; - branches[numBranches++].dst = (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + m_rowHeight / 2); - sprintf(desc, "-->%s", m_debugger->GetDescription(offs).c_str()); - dc.SetTextForeground(wxTheColourDatabase->Find("PURPLE")); // the -> arrow illustrations are purple - } - else - { - dc.SetTextForeground(*wxBLACK); - } - - dc.DrawText(StrToWxStr(dis2), 17 + 17*charWidth, rowY1); - // ------------ + hex_str = operands.substr(pos); } + if (hex_str.length() == VALID_BRANCH_LENGTH) + { + u32 offs = std::stoul(hex_str, nullptr, 16); + + branches[numBranches].src = rowY1 + m_rowHeight / 2; + branches[numBranches].srcAddr = address / m_align; + branches[numBranches++].dst = (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + m_rowHeight / 2); + desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str()); + dc.SetTextForeground(wxTheColourDatabase->Find("PURPLE")); // the -> arrow illustrations are purple + } + else + { + dc.SetTextForeground(*wxBLACK); + } + + dc.DrawText(StrToWxStr(operands), 17 + 17*charWidth, rowY1); + // ------------ + // Show blr as its' own color - if (strcmp(dis, "blr")) + if (opcode == "blr") dc.SetTextForeground(wxTheColourDatabase->Find("DARK GREEN")); else dc.SetTextForeground(wxTheColourDatabase->Find("VIOLET")); - dc.DrawText(StrToWxStr(dis), 17 + (m_plain ? 1*charWidth : 9*charWidth), rowY1); + dc.DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1*charWidth : 9*charWidth), rowY1); - if (desc[0] == 0) + if (desc.empty()) { - strcpy(desc, m_debugger->GetDescription(address).c_str()); + desc = m_debugger->GetDescription(address); } if (!m_plain) @@ -545,7 +529,7 @@ void CCodeView::OnPaint(wxPaintEvent& event) //char temp[256]; //UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE); - if (strlen(desc)) + if (!desc.empty()) { dc.DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1); } diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index dc10d4ac5c..0ef374ddbe 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -5,7 +5,6 @@ #include #include #include // Bochs -#include // Bochs #include #include #include @@ -22,6 +21,7 @@ #include #include "Common/Common.h" +#include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PPCAnalyst.h" @@ -161,9 +161,8 @@ void CJitWindow::Compare(u32 em_address) for (u32 i = 0; i < code_block.m_num_instructions; i++) { const PPCAnalyst::CodeOp &op = code_buffer.codebuffer[i]; - char temp[256]; - DisassembleGekko(op.inst.hex, op.address, temp, 256); - sptr += sprintf(sptr, "%08x %s\n", op.address, temp); + std::string temp = GekkoDisassembler::Disassemble(op.inst.hex, op.address); + sptr += sprintf(sptr, "%08x %s\n", op.address, temp.c_str()); } // Add stats to the end of the ppc box since it's generally the shortest. diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp index a2338d5bd7..25635db528 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp @@ -10,6 +10,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/Gekko.h" @@ -22,9 +23,6 @@ class wxWindow; // F-zero 80005e60 wtf?? -extern const char* GetGPRName(unsigned int index); -extern const char* GetFPRName(unsigned int index); - static const char *special_reg_names[] = { "PC", "LR", "CTR", "CR", "FPSCR", "MSR", "SRR0", "SRR1", "Exceptions", "Int Mask", "Int Cause", }; @@ -54,9 +52,9 @@ wxString CRegTable::GetValue(int row, int col) { switch (col) { - case 0: return StrToWxStr(GetGPRName(row)); + case 0: return StrToWxStr(GekkoDisassembler::GetGPRName(row)); case 1: return wxString::Format("%08x", GPR(row)); - case 2: return StrToWxStr(GetFPRName(row)); + case 2: return StrToWxStr(GekkoDisassembler::GetFPRName(row)); case 3: return wxString::Format("%016llx", riPS0(row)); case 4: return wxString::Format("%016llx", riPS1(row)); default: return wxEmptyString;