/* $VER: ppc_disasm.c V1.4 (29.08.2001) * * Disassembler module for the PowerPC microprocessor family * Copyright (c) 1998-2001 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.4 (29.08.2001) phx * AltiVec support. * v1.3 (09.03.2001) phx * Last two operands in 4-operand float instructions were swapped. * v1.2 (09.11.2000) phx * Fixed syntax of mffs, mtfsf and mtfsfi. * 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. */ #define PPC_DISASM_C #define NEG_CUTTOFF 0x8000 #include #include #include #include #include "ppc_disasm.h" static 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 char *cmpname[4] = { "cmpw","cmpd","cmplw","cmpld" }; static char *b_ext[4] = { "","l","a","la" }; static char *b_condition[8] = { "ge","le","ne","ns","lt","gt","eq","so" }; static char *b_decr[16] = { "nzf","zf",NULL,NULL,"nzt","zt",NULL,NULL, "nz","z",NULL,NULL,"nz","z",NULL,NULL }; static char *regsel[2] = { "","r" }; static char *oesel[2] = { "","o" }; static char *rcsel[2] = { "","." }; static 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 char *vmnames[] = { "mhaddshs","mhraddshs","mladduhm",NULL,"msumubm","msummbm", "msumuhm","msumuhs","msumshm","msumshs","sel","perm", "sldoi",NULL,"maddfp","nmsubfp" }; static void ierror(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(EXIT_FAILURE); } 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); dp->flags |= PPCF_ILLEGAL; } static void imm(struct DisasmPara_PPC *dp,ppc_word in,int uimm,int type) /* 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) */ { char *s; unsigned int i = (unsigned 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: if( i > NEG_CUTTOFF ) { sprintf(dp->operands,"r%d,r%d,-0x%x",(int)PPCGETD(in),(int)PPCGETA(in),0x10000u - i ); } else { sprintf(dp->operands,"r%d,r%d,0x%x",(int)PPCGETD(in),(int)PPCGETA(in),i); } break; case 1: if( i > NEG_CUTTOFF ) { sprintf(dp->operands,"r%d,r%d,-0x%x",(int)PPCGETA(in),(int)PPCGETD(in), 0x10000u - i); } else { sprintf(dp->operands,"r%d,r%d,0x%x",(int)PPCGETA(in),(int)PPCGETD(in),i); } break; case 2: if( i > NEG_CUTTOFF ) { sprintf(dp->operands,"r%d,-0x%x",(int)PPCGETA(in),0x10000u - i); } else { sprintf(dp->operands,"r%d,0x%x",(int)PPCGETA(in),i); } break; case 3: if( i > NEG_CUTTOFF ) { sprintf(dp->operands,"r%d,-0x%x",(int)PPCGETD(in),0x10000u - i); } else { sprintf(dp->operands,"r%d,0x%x",(int)PPCGETD(in),i); } break; default: ierror("imm(): Wrong type"); break; } } static void ra_rb(char *s,ppc_word in) { sprintf(s,"r%d,r%d",(int)PPCGETA(in),(int)PPCGETB(in)); } static char *rd_ra_rb(char *s,ppc_word in,int mask) { static const char *fmt = "r%d,"; if (mask) { if (mask & 4) s += sprintf(s,fmt,(int)PPCGETD(in)); if (mask & 2) s += sprintf(s,fmt,(int)PPCGETA(in)); if (mask & 1) s += sprintf(s,fmt,(int)PPCGETB(in)); *--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 = "r%d,"; if (mask) { if (mask & 4) s += sprintf(s,ffmt,(int)PPCGETD(in)); if (mask & 2) s += sprintf(s,rfmt,(int)PPCGETA(in)); if (mask & 1) s += sprintf(s,rfmt,(int)PPCGETB(in)); *--s = '\0'; } else *s = '\0'; return (s); } static char *vd_va_vb(char *s,ppc_word in,int mask) { static const char *fmt = "v%d,"; if (mask) { if (mask & 4) s += sprintf(s,fmt,(int)PPCGETD(in)); if (mask & 2) { if (mask & 16) { /* A = SIMM */ int a = PPCGETA(in); s += sprintf(s,fmt+1,(a>15)?(a-32):a); } else if (mask & 8) /* A = UIMM */ s += sprintf(s,fmt+1,(int)PPCGETA(in)); else s += sprintf(s,fmt,(int)PPCGETA(in)); } if (mask & 1) s += sprintf(s,fmt,(int)PPCGETB(in)); *--s = '\0'; } else *s = '\0'; return (s); } static void trapi(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) { 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); } 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); dp->operands = oper; } else ill(dp,in); } static void addi(struct DisasmPara_PPC *dp,ppc_word in,char *ext) { if ((in&0x08000000) && !PPCGETA(in)) { sprintf(dp->opcode,"l%s",ext); /* li, lis */ imm(dp,in,0,3); } else { sprintf(dp->opcode,"%s%s",(in&0x8000)?"sub":"add",ext); if (in & 0x8000) in = (in^0xffff) + 1; imm(dp,in,1,0); } } static int branch(struct DisasmPara_PPC *dp,ppc_word in, 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; 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,"0x%x,0x%x",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,"0x%x",bi); } return (opercnt); } static void bc(struct DisasmPara_PPC *dp,ppc_word in) { int d = (int)(in & 0xfffc); int offs; char *oper = dp->operands; if (d >= 0x8000) d -= 0x10000; if (offs = branch(dp,in,"",(in&2)?1:0,d)) { oper += offs; *oper++ = ','; } if (in & 2) /* AA ? */ sprintf(dp->operands,"0x%lx",(unsigned long)d); else sprintf(oper,"0x%lx",(unsigned long)((char *)dp->iaddr + d)); dp->type = PPCINSTR_BRANCH; dp->displacement = (ppc_word)d; } static void bli(struct DisasmPara_PPC *dp,ppc_word in) { int d = (int)(in & 0x3fffffc); if (d >= 0x2000000) d -= 0x4000000; sprintf(dp->opcode,"b%s",b_ext[in&3]); if (in & 2) /* AA ? */ sprintf(dp->operands,"0x%lx",(unsigned long)d); else sprintf(dp->operands,"0x%lx",(unsigned long)((char *)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,char *n1,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,char *name, unsigned char dmode) { if (in & (PPCDMASK|PPCAMASK|PPCBMASK|1)) { ill(dp,in); } else { dp->flags |= dmode; strcpy(dp->opcode,name); } } static void rlw(struct DisasmPara_PPC *dp,ppc_word in,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,"r%d,r%d,%s%d,%d,%d",a,s,regsel[i],bsh,mb,me); } static void ori(struct DisasmPara_PPC *dp,ppc_word in,char *name) { strcpy(dp->opcode,name); imm(dp,in,1,1); } static void rld(struct DisasmPara_PPC *dp,ppc_word in,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,"r%d,r%d,%s%d,%d",a,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) { 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,char *name,int mask, int smode,int chkoe,int chkrc,unsigned char dmode) /* standard instruction: xxxx rD,rA,rB */ { if (chkrc>=0 && (in&1)!=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,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)!=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,"r%d",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,"0x%x,r%d",sr,s); else sprintf(dp->operands,"r%d,0x%x",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; 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; case 18: x = "dsisr"; break; case 19: x = "dar"; break; case 22: x = "dec"; break; case 25: x = "sdr1"; break; case 26: x = "srr0"; break; case 27: x = "srr1"; break; case 272: case 273: case 274: case 275: x = "sprg"; spr -= 272; fmt = 1; break; case 280: x = "asr"; break; case 282: x = "ear"; break; case 284: x = "tbl"; break; case 285: x = "tbu"; break; case 528: case 530: case 532: case 534: x = "ibatu"; spr = (spr-528)>>1; fmt = 1; break; case 529: case 531: case 533: case 535: x = "ibatl"; spr = (spr-529)>>1; fmt = 1; break; case 536: case 538: case 540: case 542: x = "dbatu"; spr = (spr-536)>>1; fmt = 1; break; case 537: case 539: case 541: case 543: x = "dbatl"; spr = (spr-537)>>1; fmt = 1; break; case 1013: x = "dabr"; break; default: x = "spr"; fmt = 1; break; } sprintf(dp->opcode,"m%c%s",smode?'t':'f',x); if (fmt) { if (smode) sprintf(dp->operands,"0x%x,r%d",spr,d); else sprintf(dp->operands,"r%d,0x%x",d,spr); } else sprintf(dp->operands,"r%d",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,"r%d",d); switch (tbr) { case 268: x = 'l'; break; case 269: x = 'u'; break; default: x = '\0'; dp->flags |= PPCF_SUPER; sprintf(s,",0x%x",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,"r%d,r%d,%d",a,s,bsh); } static void ldst(struct DisasmPara_PPC *dp,ppc_word in,char *name, char reg,unsigned char dmode) { int s = (int)PPCGETD(in); int a = (int)PPCGETA(in); unsigned 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( d > NEG_CUTTOFF ) { sprintf(dp->operands,"%c%d,-0x%x(r%d)",reg,s, 0x10000u - d,a); } else { sprintf(dp->operands,"%c%d,0x%x(r%d)",reg,s,d,a); } } static void fdabc(struct DisasmPara_PPC *dp,ppc_word in,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 & 1) s += sprintf(s,fmt,(int)PPCGETC(in)); else if (!(mask&8)) err |= (int)PPCGETC(in); if (mask & 2) s += sprintf(s,fmt,(int)PPCGETB(in)); else if (PPCGETB(in)) err |= (int)PPCGETB(in); *(s-1) = '\0'; if (err) ill(dp,in); } static void fdab(struct DisasmPara_PPC *dp,ppc_word in,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)); } } static void vdab(struct DisasmPara_PPC *dp,ppc_word in,char *name, int mask,int chkrc) /* standard AltiVec instruction: vxxx vD,vA,vB */ { sprintf(dp->opcode,"%s%s",name,rcsel[chkrc&&(in&PPCVRC)]); vd_va_vb(dp->operands,in,mask); } static void vdabc(struct DisasmPara_PPC *dp,ppc_word in) /* four operands AltiVec instruction: vxxx vD,vA,vB,vC */ { int nameidx = (in & 0x3f) - 32; if (vmnames[nameidx]) { sprintf(dp->opcode,"v%s",vmnames[nameidx]); sprintf(vd_va_vb(dp->operands,in,7), (nameidx==12) ? ",%d" : ",v%d", (int)PPCGETC(in)); } else ill(dp,in); } static void vldst(struct DisasmPara_PPC *dp,ppc_word in,char *name) { if (in & 1) { ill(dp,in); } else { dp->flags |= PPCF_ALTIVEC; strcpy(dp->opcode,name); sprintf(dp->operands,"v%d,r%d,r%d",(int)PPCGETD(in), (int)PPCGETA(in),(int)PPCGETB(in)); } } static void dstrm(struct DisasmPara_PPC *dp,ppc_word in,char *name) { if (in & 0x01800001) { ill(dp,in); } else { char *s = dp->operands;; if (PPCGETIDX2(in) == 822) { /* dss, dssall */ if (PPCGETA(in) || PPCGETB(in)) { ill(dp,in); return; } sprintf(dp->opcode,"d%s%s",name,(in&PPCDST) ? "all" : ""); } else { sprintf(dp->opcode,"d%s%c",name,(in&PPCDST) ? 't' : '\0'); s += sprintf(s,"r%d,r%d,",(int)PPCGETA(in),(int)PPCGETB(in)); } sprintf(s,"%d",(int)PPCGETSTRM(in)); dp->flags |= PPCF_ALTIVEC; } } #ifdef PPC_GEKKO static void gps2(struct DisasmPara_PPC *dp,ppc_word in,char *name,short pcount) { int d=PPCGETD(in); int c=PPCGETC(in); int a=PPCGETA(in); int b=PPCGETB(in); sprintf(dp->opcode,"ps_%s",name); if(pcount == 3) sprintf(dp->operands,"f%d,f%d,f%d",d,a,c); else sprintf(dp->operands,"f%d,f%d,f%d,f%d",d,a,c,b); } static void gps(struct DisasmPara_PPC *dp,ppc_word in,char *name,short pcount,short dlength) { int d; if(dlength==5) d=PPCGETD(in); else d=PPCGETCRD(in); int a=PPCGETA(in); int b=PPCGETB(in); sprintf(dp->opcode,"ps_%s",name); if(pcount == 2) sprintf(dp->operands,"f%d,f%d",d,b); else sprintf(dp->operands,"f%d,f%d,f%d",d,a,b); } static void psqx(struct DisasmPara_PPC *dp,ppc_word in,char *name) { int a=PPCGETA(in); int b=PPCGETB(in); int d=PPCGETD(in); int w=GEKKOGETW(in); int i=GEKKOGETI(in); sprintf(dp->opcode,"psq_%sx",name); sprintf(dp->operands,"f%d,r%d,r%d,%d,%d",d,a,b,w,i); } static void psq(struct DisasmPara_PPC *dp,ppc_word in,char *name) { int a=PPCGETA(in); int d=PPCGETD(in); int w=GEKKOGETW2(in); int i=GEKKOGETI2(in); int v=GEKKOGETV(in); sprintf(dp->opcode,"psq_%s",name); sprintf(dp->operands,"f%d,%d(r%d),%d,%d",d,v,a,w,i); } #endif 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 */ #ifdef 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 2: trapi(dp,in,PPCF_64); /* tdi */ break; case 3: trapi(dp,in,0); /* twi */ break; case 4: dp->flags |= PPCF_ALTIVEC; #ifndef PPC_GEKKO if ((in & 0x30) == 0x20) { /* vxxx vA,vB,vC,vD - four operands instructions */ vdabc(dp,in); break; } #endif if (in & 1) { ill(dp,in); break; } switch (PPCGETIDX2(in)<<1) { #ifdef PPC_GEKKO case 42: gps(dp,in,"add",3,5); break; case 36: gps(dp,in,"div",3,5); break; case 40: gps(dp,in,"sub",3,5); break; case 1056: gps(dp,in,"merge00",3,5); break; case 1120: gps(dp,in,"merge01",3,5); break; case 1184: gps(dp,in,"merge10",3,5); break; case 1248: gps(dp,in,"merge11",3,5); break; case 144: gps(dp,in,"mr",2,5); break; case 272: gps(dp,in,"nabs",2,5); break; case 80: gps(dp,in,"neg",2,5); break; case 26: gps(dp,in,"res",2,5); break; case 52: gps(dp,in,"rsqrte",2,5); break; case 0: gps(dp,in,"cmpu0",3,3); break; case 64: gps(dp,in,"cmpo0",3,3); break; case 128: gps(dp,in,"cmpu1",3,3); break; case 192: gps(dp,in,"cmpo1",3,3); break; case 528: gps(dp,in,"abs",2,5); break; #endif #ifndef PPC_GEKKO case 0: vdab(dp,in,"vaddubm",7,0); break; #endif case 2: vdab(dp,in,"vmaxub",7,0); break; case 4: vdab(dp,in,"vrlb",7,0); break; case 6: case 6+PPCVRC: vdab(dp,in,"vcmpequb",7,1); break; case 8: vdab(dp,in,"vmuloub",7,0); break; case 10: vdab(dp,in,"vaddfp",7,0); break; case 12: vdab(dp,in,"vmrghb",7,0); break; case 14: vdab(dp,in,"vpkuhum",7,0); break; #ifndef PPC_GEKKO case 64: vdab(dp,in,"vadduhm",7,0); break; #endif case 66: vdab(dp,in,"vmaxuh",7,0); break; case 68: vdab(dp,in,"vrlh",7,0); break; case 70: case 70+PPCVRC: vdab(dp,in,"vcmpequh",7,1); break; case 72: vdab(dp,in,"vmulouh",7,0); break; case 74: vdab(dp,in,"vsubfp",7,0); break; case 76: vdab(dp,in,"vmrghh",7,0); break; case 78: vdab(dp,in,"vpkuwum",7,0); break; #ifndef PPC_GEKKO case 128: vdab(dp,in,"vadduwm",7,0); break; #endif case 130: vdab(dp,in,"vmaxuw",7,0); break; case 132: vdab(dp,in,"vrlw",7,0); break; case 134: case 134+PPCVRC: vdab(dp,in,"vcmpequw",7,1); break; case 140: vdab(dp,in,"vmrghw",7,0); break; case 142: vdab(dp,in,"vpkuhus",7,0); break; case 198: case 198+PPCVRC: vdab(dp,in,"vcmpeqfp",7,1); break; case 206: vdab(dp,in,"vpkuwus",7,0); break; case 258: vdab(dp,in,"vmaxsb",7,0); break; case 260: vdab(dp,in,"vslb",7,0); break; case 264: vdab(dp,in,"vmulosb",7,0); break; case 266: vdab(dp,in,"vrefp",5,0); break; case 268: vdab(dp,in,"vmrglb",7,0); break; case 270: vdab(dp,in,"vpkshus",7,0); break; case 322: vdab(dp,in,"vmaxsh",7,0); break; case 324: vdab(dp,in,"vslh",7,0); break; case 328: vdab(dp,in,"vmulosh",7,0); break; case 330: vdab(dp,in,"vrsqrtefp",5,0); break; case 332: vdab(dp,in,"vmrglh",7,0); break; case 334: vdab(dp,in,"vpkswus",7,0); break; case 384: vdab(dp,in,"vaddcuw",7,0); break; case 386: vdab(dp,in,"vmaxsw",7,0); break; case 388: vdab(dp,in,"vslw",7,0); break; case 394: vdab(dp,in,"vexptefp",5,0); break; case 396: vdab(dp,in,"vmrglw",7,0); break; case 398: vdab(dp,in,"vpkshss",7,0); break; case 452: vdab(dp,in,"vsl",7,0); break; case 454: case 454+PPCVRC: vdab(dp,in,"vcmpgefp",7,1); break; case 458: vdab(dp,in,"vlogefp",5,0); break; case 462: vdab(dp,in,"vpkswss",7,0); break; case 512: vdab(dp,in,"vaddubs",7,0); break; case 514: vdab(dp,in,"vminub",7,0); break; case 516: vdab(dp,in,"vsrb",7,0); break; case 518: case 518+PPCVRC: vdab(dp,in,"vcmpgtub",7,1); break; case 520: vdab(dp,in,"vmuleub",7,0); break; case 522: vdab(dp,in,"vrfin",5,0); break; case 524: vdab(dp,in,"vspltb",15,0); break; case 526: vdab(dp,in,"vupkhsb",5,0); break; case 576: vdab(dp,in,"vadduhs",7,0); break; case 578: vdab(dp,in,"vminuh",7,0); break; case 580: vdab(dp,in,"vsrh",7,0); break; case 582: case 582+PPCVRC: vdab(dp,in,"vcmpgtuh",7,1); break; case 584: vdab(dp,in,"vmuleuh",7,0); break; case 586: vdab(dp,in,"vrfiz",5,0); break; case 588: vdab(dp,in,"vsplth",15,0); break; case 590: vdab(dp,in,"vupkhsh",5,0); break; case 640: vdab(dp,in,"vadduws",7,0); break; case 642: vdab(dp,in,"vminuw",7,0); break; case 644: vdab(dp,in,"vsrw",7,0); break; case 646: case 646+PPCVRC: vdab(dp,in,"vcmpgtuw",7,1); break; case 650: vdab(dp,in,"vrfip",5,0); break; case 652: vdab(dp,in,"vspltw",15,0); break; case 654: vdab(dp,in,"vupklsb",5,0); break; case 708: vdab(dp,in,"vsr",7,0); break; case 710: case 710+PPCVRC: vdab(dp,in,"vcmpgtfp",7,1); break; case 714: vdab(dp,in,"vrfim",5,0); break; case 718: vdab(dp,in,"vupklsh",5,0); break; case 768: vdab(dp,in,"vaddsbs",7,0); break; case 770: vdab(dp,in,"vminsb",7,0); break; case 772: vdab(dp,in,"vsrab",7,0); break; case 774: case 774+PPCVRC: vdab(dp,in,"vcmpgtsb",7,1); break; case 776: vdab(dp,in,"vmulesb",7,0); break; case 778: vdab(dp,in,"vcfux",15,0); break; case 780: vdab(dp,in,"vspltisb",22,0); break; case 782: vdab(dp,in,"vpkpx",7,0); break; case 832: vdab(dp,in,"vaddshs",7,0); break; case 834: vdab(dp,in,"vminsh",7,0); break; case 836: vdab(dp,in,"vsrah",7,0); break; case 838: case 838+PPCVRC: vdab(dp,in,"vcmpgtsh",7,1); break; case 840: vdab(dp,in,"vmulesh",7,0); break; case 842: vdab(dp,in,"vcfsx",15,0); break; case 844: vdab(dp,in,"vspltish",22,0); break; case 846: vdab(dp,in,"vupkhpx",5,0); break; case 896: vdab(dp,in,"vaddsws",7,0); break; case 898: vdab(dp,in,"vminsw",7,0); break; case 900: vdab(dp,in,"vsraw",7,0); break; case 902: case 902+PPCVRC: vdab(dp,in,"vcmpgtsw",7,1); break; case 906: vdab(dp,in,"vctuxs",15,0); break; case 908: vdab(dp,in,"vspltisw",22,0); break; case 966: case 966+PPCVRC: vdab(dp,in,"vcmpbfp",7,1); break; case 970: vdab(dp,in,"vctsxs",15,0); break; case 974: vdab(dp,in,"vupklpx",5,0); break; case 1024: vdab(dp,in,"vsububm",7,0); break; case 1026: vdab(dp,in,"vavgub",7,0); break; case 1028: vdab(dp,in,"vand",7,0); break; case 1034: vdab(dp,in,"vmaxfp",7,0); break; case 1036: vdab(dp,in,"vslo",7,0); break; case 1088: vdab(dp,in,"vsubuhm",7,0); break; case 1090: vdab(dp,in,"vavguh",7,0); break; case 1092: vdab(dp,in,"vandc",7,0); break; case 1098: vdab(dp,in,"vminfp",7,0); break; case 1100: vdab(dp,in,"vsro",7,0); break; case 1152: vdab(dp,in,"vsubuwm",7,0); break; case 1154: vdab(dp,in,"vavguw",7,0); break; case 1156: vdab(dp,in,"vor",7,0); break; case 1220: vdab(dp,in,"vxor",7,0); break; case 1282: vdab(dp,in,"vavgsb",7,0); break; case 1284: vdab(dp,in,"vnor",7,0); break; case 1346: vdab(dp,in,"vavgsh",7,0); break; case 1408: vdab(dp,in,"vsubcuw",7,0); break; case 1410: vdab(dp,in,"vavgsw",7,0); break; case 1536: vdab(dp,in,"vsububs",7,0); break; case 1540: vdab(dp,in,"mfvscr",4,0); break; case 1544: vdab(dp,in,"vsum4ubs",7,0); break; case 1600: vdab(dp,in,"vsubuhs",7,0); break; case 1604: vdab(dp,in,"mtvscr",1,0); break; case 1608: vdab(dp,in,"vsum4shs",7,0); break; case 1664: vdab(dp,in,"vsubuws",7,0); break; case 1672: vdab(dp,in,"vsum2sws",7,0); break; case 1792: vdab(dp,in,"vsubsbs",7,0); break; case 1800: vdab(dp,in,"vsum4sbs",7,0); break; case 1856: vdab(dp,in,"vsubshs",7,0); break; case 1920: vdab(dp,in,"vsubsws",7,0); break; case 1928: vdab(dp,in,"vsumsws",7,0); break; #ifndef PPC_GEKKO default: ill(dp,in); break; #endif #ifdef PPC_GEKKO default: switch(PPCGETM(in)) { case 10: gps2(dp,in,"sum0",4); break; case 11: gps2(dp,in,"sum1",4); break; case 12: gps2(dp,in,"muls0",3); break; case 13: gps2(dp,in,"muls1",3); break; case 14: gps2(dp,in,"madds0",4); break; case 15: gps2(dp,in,"madds1",4); break; case 23: gps2(dp,in,"sel",4); break; case 25: gps2(dp,in,"mul",3); break; case 28: gps2(dp,in,"msub",4); break; case 29: gps2(dp,in,"madd",4); break; case 30: gps2(dp,in,"nmadd",4); break; case 31: gps2(dp,in,"nmsub",4); break; case 6: case 7: switch(GEKKOGETLASID(in)) { case 6: psqx(dp,in,"l"); break; case 7: psqx(dp,in,"st"); break; case 38: psqx(dp,in,"lu"); break; case 39: psqx(dp,in,"stu"); break; default: ill(dp,in); break; } break; default: ill(dp,in); break; } break; #endif } break; case 7: strcpy(dp->opcode,"mulli"); imm(dp,in,0,0); break; case 8: strcpy(dp->opcode,"subfic"); imm(dp,in,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 6: vldst(dp,in,"lvsl"); /* AltiVec */ break; case 7: vldst(dp,in,"lvebx"); /* AltiVec */ 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 38: vldst(dp,in,"lvsr"); /* AltiVec */ break; case 39: vldst(dp,in,"lvehx"); /* AltiVec */ 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 71: vldst(dp,in,"lvewx"); /* AltiVec */ 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 103: vldst(dp,in,"lvx"); /* AltiVec */ 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 135: vldst(dp,in,"stvebx"); /* AltiVec */ 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 167: vldst(dp,in,"stvehx"); /* AltiVec */ 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 199: vldst(dp,in,"stvewx"); /* AltiVec */ 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 231: vldst(dp,in,"stvx"); /* AltiVec */ 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 342: dstrm(dp,in,"st"); /* AltiVec Stream */ break; case 343: dab(dp,in,"lhax",7,0,0,0,0); break; case 359: vldst(dp,in,"lvxl"); /* AltiVec */ 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 374: dstrm(dp,in,"stst"); /* AltiVec Stream */ 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 487: vldst(dp,in,"stvxl"); /* AltiVec */ 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 822: dstrm(dp,in,"ss"); /* AltiVec Stream */ 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; #ifdef PPC_GEKKO case 56: psq(dp,in,"l"); break; case 57: psq(dp,in,"lu"); break; #endif 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; #ifdef PPC_GEKKO case 60: psq(dp,in,"st"); break; case 61: psq(dp,in,"stu"); break; #endif 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,"sqrte",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,"%d,0x%x",(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))) { sprintf(dp->opcode,"mffs%s",rcsel[in&1]); sprintf(dp->operands,"f%d",(int)PPCGETD(in)); } else ill(dp,in); break; case 711: if (!(in & 0x02010000)) { sprintf(dp->opcode,"mtfsf%s",rcsel[in&1]); sprintf(dp->operands,"0x%x,f%d", (int)(in & 0x01fe0000)>>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); }