/* $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 long 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 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 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) { // strcpy(dp->opcode,".word"); // sprintf(dp->operands,"0x%08lx",(unsigned long)in); strcpy(dp->opcode,""); sprintf(dp->operands,""); 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)]) { 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 long 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 long)d); else sprintf(oper,"->0x%.8X",(unsigned long)(*dp->iaddr) + d); dp->type = PPCINSTR_BRANCH; dp->displacement = (ppc_word)d; } static void bli(struct DisasmPara_PPC *dp,ppc_word in) { unsigned long d = (unsigned long)(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 long)d); else sprintf(dp->operands,"->0x%.8X",(unsigned long)(*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_Mask(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) return ~mask; else return mask; } 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_Mask(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 long 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 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) { ppc_word pc = *dp->iaddr; 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, FB); 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", FD); return; case 32: strcpy(op,"ps_cmpq0"); sprintf(pr, "ps_cmpo0", FD); return; case 64: strcpy(op,"ps_cmpu1"); sprintf(pr, "ps_cmpu1", FD); return; case 96: strcpy(op,"ps_cmpo1"); sprintf(pr, "ps_cmpo1", FD); 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"); sprintf(pr, ""); return; } // default: sprintf(op, "ps_%i",((inst>>1)&0x1f)); strcpy(pr,"---"); return; } static void ps_mem(struct DisasmPara_PPC *dp,ppc_word inst) { ppc_word pc = *dp->iaddr; 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"); sprintf(pr, "", FD); 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==NULL || dp->operands==NULL) 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 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",6,0); break; case 40: fdabc(dp,in,"subs",6,0); break; case 42: fdabc(dp,in,"adds",6,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",5,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",6,0); break; case 8: fdabc(dp,in,"sub",6,0); break; case 10: fdabc(dp,in,"add",6,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",5,0); break; case 20: fdabc(dp,in,"rsqrte",2,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; default: ill(dp,in); break; } } else { switch (PPCGETIDX2(in)) { case 0: fcmp(dp,in,'u'); break; case 12: fdabc(dp,in,"rsp",10,0); break; case 14: fdabc(dp,in,"ctiw",10,0); break; case 15: fdabc(dp,in,"ctiwz",10,0); 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: fdabc(dp,in,"mr",10,0); 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); } } // --------------------------------------------------------------------------- // simplified interface const char *DisassembleGekko(unsigned int opcode, unsigned int curInstAddr) { char opcodeStr[64], operandStr[64]; PPCDisasm::DisasmPara_PPC dp; static char buf[128]; static 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); //sprintf(buf, "%-10s %s", opcodeStr, operandStr); sprintf(buf, "%s\t%s", opcodeStr, operandStr); return buf; } static const char *gprnames[] = { "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", "r08", "r09", "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; }