From ecea71b49d35e83c95792248f0f67cdfe35daac4 Mon Sep 17 00:00:00 2001 From: giantpune Date: Tue, 13 Dec 2011 06:07:45 +0000 Subject: [PATCH] * symbolizer: follow global variables from known functions to identify the unknown ones --- .gitattributes | 2 + symbolizer/main.cpp | 227 ++- symbolizer/ppc_disasm.c | 2807 +++++++++++++++++++++++++++++++++++++ symbolizer/ppc_disasm.h | 143 ++ symbolizer/symbolizer.pro | 6 +- 5 files changed, 3178 insertions(+), 7 deletions(-) create mode 100644 symbolizer/ppc_disasm.c create mode 100644 symbolizer/ppc_disasm.h diff --git a/.gitattributes b/.gitattributes index bdc3743..b080243 100644 --- a/.gitattributes +++ b/.gitattributes @@ -141,6 +141,8 @@ symbolizer/dol.h -text symbolizer/elfparser.cpp -text symbolizer/elfparser.h -text symbolizer/main.cpp -text +symbolizer/ppc_disasm.c -text +symbolizer/ppc_disasm.h -text symbolizer/symbolizer.pro -text thp_player/ffw.png -text thp_player/gcvid.cpp -text diff --git a/symbolizer/main.cpp b/symbolizer/main.cpp index d4253ed..bcb1fa9 100644 --- a/symbolizer/main.cpp +++ b/symbolizer/main.cpp @@ -2,6 +2,7 @@ #include "dol.h" #include "elfparser.h" +#include "ppc_disasm.h" #include "../WiiQt/includes.h" #include "../WiiQt/tools.h" @@ -30,6 +31,16 @@ struct KnownFunction } }; +#define GLOBALVAR_MASK( x ) ( (quint32)( x & ( PPCAMASK | 0xffff ) ) ) +// keep track of known rtoc & r13 references +struct KnownVariable +{ + quint32 sig; // signature for opcodes dealing with this variable when GLOBALVAR_MASK()'d + //! given lwz %r0, -0x5460(%r13), it will store the -0x5460(%r13) + QString name; // symbol name + ElfParser::File *file; // pointer to the file object that contains the data +}; + // holds the info about a dol to use while searching for crap in it Dol dol; QStringList dolTextHex;// store a copy of the dol as hex for easier searching for patterns @@ -42,15 +53,33 @@ QList< ElfParser::File > libFiles; QList< KnownData > knownData; QList< KnownFunction > knownFunctions; +// keep track of variables accessed through r2 and r13 +QList< KnownVariable > knownVariables; + // keep a list of the locations that each function's pattern matched to keep from looking them up over and over QMap< const ElfParser::Function *, QList< quint32 > >patternMatches; +#define DU32( x ) qDebug().nospace() << #x << ": " << hex << (x) + QString NStr( quint32 num, quint8 width = 8 ); QString NStr( quint32 num, quint8 width ) { return QString( "%1" ).arg( num, width, 16, QChar( '0' ) ); } +bool IsVariableKnown( quint32 sig, const QList< KnownVariable > &list = knownVariables ); +bool IsVariableKnown( quint32 sig, const QList< KnownVariable > &list ) +{ + foreach( const KnownVariable &var, list ) + { + if( var.sig == sig ) + { + return true; + } + } + return false; +} + // read dol into memory bool LoadDol( const QString &path ) { @@ -942,6 +971,177 @@ void TryToMatchFunctions1() RemoveOverlaps(); } +void FindGlobalVariables() +{ + QList< QPair< const ElfParser::Function *, const KnownData *> > maybeMatches;// keep track of functions to check + //QList< QPair< QPair< const ElfParser::Function *, const KnownData *> *, const SymAlias * > > aliasMatches;// keep track of functions to check via aliases + + QMap< const ElfParser::Function *, const ElfParser::File * >fileMap; + QMap< const ElfParser::Function *, quint32 >winners; + + QList< KnownVariable > newVariables; + + foreach( const KnownFunction &kf1, knownFunctions )// look in all known functions for global variables + { + if( !kf1.file ) + { + continue; + } + foreach( const SymRef &ref, kf1.function->References() ) + { + if( ref.type != SymRef::R_PPC_EMB_SDA21 ) + { + continue; + } + quint32 addr = kf1.addr + ( ref.off & ~3 ); + quint32 opcode = GetOpcodeFromAddr( addr ); + if( opcode == 0xdeadbeef ) + { + DBG << "opcode" << hex << opcode; + continue; + } + quint32 reg = (quint32)PPCGETA( opcode ); + if( reg != 2 && reg != 13 ) + { + DBG << "reg:" << hex << reg << kf1.function->Name() << ref.name; + continue; + } + quint32 sig = GLOBALVAR_MASK( opcode ); + if( IsVariableKnown( sig, newVariables ) || IsVariableKnown( sig ) ) + { + continue; + } + KnownVariable nw; + nw.file = (ElfParser::File *)kf1.file; + nw.name = ref.name; + nw.sig = sig; + newVariables << nw; + + /*qDebug() << "opcode" << hex << opcode << "addr" << addr; + qDebug() << kf1.function->Name() << ref.name; + qDebug(); + quint32 z = GLOBALVAR_MASK( opcode ); + opcode = z; + quint32 s = (quint32)PPCGETD( opcode ); + quint32 a = (quint32)PPCGETA( opcode ); + quint32 d = (quint32)( opcode & 0xffff ); + quint32 o = (quint32)( PPCGETIDX( opcode ) - 32 ); + DU32( o ); + DU32( d ); + DU32( s ); + DU32( a );*/ + //exit( 0 ); + } + } + + // look at all the variables and see if there is an unknown function in that file that refers to the variable + + QList< const ElfParser::Function * > bitches; + foreach( const KnownVariable &var, newVariables ) + { + foreach( const ElfParser::Function &fun, var.file->Functions() ) + { + if( FunctionIsKnown( &fun ) ) + { + continue; + } + foreach( const SymRef &ref, fun.References() ) + { + if( ref.type != SymRef::R_PPC_EMB_SDA21 ) + { + continue; + } + if( ref.name != var.name ) + { + continue; + } + if( !bitches.contains( &fun ) ) + { + bitches << &fun; + fileMap[ &fun ] = var.file; + } + } + } + } + + // now look at all the references to global variables in each found function and if it refers to a known one, + // check the opcode and see that it is correct + QMapIterator< const ElfParser::Function *, const ElfParser::File * > it( fileMap ); + while( it.hasNext() ) + { + it.next(); + QList< quint32 > addrs = PatternMatches( it.key() ); + quint32 winner = 0; + bool functionFailed = false; + foreach( quint32 addr, addrs ) + { + bool fail = false; + foreach( const SymRef &ref, it.key()->References() ) + { + if( ref.type != SymRef::R_PPC_EMB_SDA21 ) + { + continue; + } + quint32 varSig = 0xb00b5; + foreach( const KnownVariable &kv, newVariables ) + { + if( kv.file == it.value() && kv.name == ref.name ) + { + varSig = kv.sig; + break; + } + } + if( varSig == 0xb00b5 )// we dont know this variable + { + continue; + } + quint32 opAddr = addr + ( ref.off & ~3 ); + quint32 opcode = GetOpcodeFromAddr( opAddr ); + if( opcode == 0xdeadbeef ) + { + DBG << "opcode" << hex << opcode; + continue; + } + if( GLOBALVAR_MASK( opcode ) != varSig ) + { + fail = true; + break; + } + } + if( fail ) + { + continue; + } + if( winner )// found more than 1 match for this little guy + { + functionFailed = true; + break; + } + winner = addr; + } + if( winner && !functionFailed ) + { + winners[ it.key() ] = winner; + } + } + + knownVariables << newVariables; + + //DBG << "added these bad boys"; + QMapIterator< const ElfParser::Function *, quint32 > ret( winners ); + while( ret.hasNext() ) + { + ret.next(); + //qDebug() << hex << ret.value() + // << NStr( ret.key()->Pattern().size() / 2, 4 ) + // << ret.key()->Name() + // << fileMap.find( ret.key() ).value()->Name(); + AddFunctionToKnownList( ret.key(), fileMap.find( ret.key() ).value(), ret.value() ); + } + RemoveOverlaps(); + +} + void TryToMatchFunctions2( QMap< const ElfParser::Function *, quint32 > &nonMatchingBranches ) { QStringList wholeDolHex = dolDataHex + dolTextHex; @@ -1290,11 +1490,11 @@ QList< QPair< const ElfParser::Function *, quint32> > TryToMatchFunctions4( QLis // cleanup the list CleanupList( maybeMatches ); int s = maybeMatches.size(); - qDebug() << "Functions that only have 1 pattern match, contain wildcards, and are larger than 0x" << hex << minLen << "bytes:"; + //qDebug() << "Functions that only have 1 pattern match, contain wildcards, and are larger than 0x" << hex << minLen << "bytes:"; for( int i = 0; i < s; i++ ) { const QPair< const ElfParser::Function *, quint32 > &p = maybeMatches.at( i ); - qDebug() << hex << p.second << NStr( p.first->Pattern().size() / 2, 4 ) << p.first->Name(); + //qDebug() << hex << p.second << NStr( p.first->Pattern().size() / 2, 4 ) << p.first->Name(); AddFunctionToKnownList( p.first, fileMap.find( p.first ).value(), p.second ); } @@ -1518,8 +1718,10 @@ int main(int argc, char *argv[]) //dolPath = "/home/j/c/hackmiiHaxx/disassembly/mem1-decrypt_60.bin"; //libPath = "/home/j/devkitPRO/libogc/lib/wii"; + //dolPath = "/home/j/c/WiiQt/93/symbolizer/00000043_60.dol"; //dolPath = "/home/j/c/WWE12_haxx/main.dol"; //libPath = "/home/j/devkitPRO/libogc/lib/wii"; + //libPath += "/os.a"; qDebug() << "Loading dol..."; if( !LoadDol( dolPath ) ) @@ -1544,9 +1746,15 @@ int main(int argc, char *argv[]) // find first round of functions TryToMatchFunctions1(); + // add functions by looking at rtoc and r13 + FindGlobalVariables(); + //exit( 0 ); + // find branches from the first round of functions TryToMatchFunctions2( nonMatchingBranches ); + FindGlobalVariables(); + // looking for functions that dont branch anywhere or use global variables or anything TryToMatchFunctions0(); @@ -1565,6 +1773,11 @@ int main(int argc, char *argv[]) qDebug() << " - added" << newFunctions.size() << "new functions -"; } + // add functions by looking at rtoc and r13 + FindGlobalVariables(); + + + qDebug() << "Total functions found:" << knownFunctions.size(); // find branches from the known functions @@ -1591,9 +1804,12 @@ int main(int argc, char *argv[]) num = knownFunctions.size(); for( int i = 0; i < maxRetries; i++ ) { - qDebug() << " -- Round" << i << '/' << maxRetries << " following branches --"; + qDebug() << " -- Round" << i << '/' << maxRetries << " following branches and global variables --"; TryToMatchFunctions2( nonMatchingBranches ); + // add functions by looking at rtoc and r13 + FindGlobalVariables(); + int num2 = knownFunctions.size(); if( num2 == num ) { @@ -1603,8 +1819,9 @@ int main(int argc, char *argv[]) num = num2; } - qDebug() << "Total data matches: " << knownData.size(); - qDebug() << "Total functions found:" << knownFunctions.size(); + qDebug() << "Total global variables: " << knownVariables.size(); + qDebug() << "Total data matches: " << knownData.size(); + qDebug() << "Total functions found: " << knownFunctions.size(); qDebug() << "Generating idc file..."; QString idc = MakeIDC( dolPath, libPath, nonMatchingBranches ); diff --git a/symbolizer/ppc_disasm.c b/symbolizer/ppc_disasm.c new file mode 100644 index 0000000..ca312a8 --- /dev/null +++ b/symbolizer/ppc_disasm.c @@ -0,0 +1,2807 @@ +/* $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); +} diff --git a/symbolizer/ppc_disasm.h b/symbolizer/ppc_disasm.h new file mode 100644 index 0000000..caba0d6 --- /dev/null +++ b/symbolizer/ppc_disasm.h @@ -0,0 +1,143 @@ +/* $VER: ppc_disasm.h 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. + * v0.1 (23.05.1998) phx + * First version, which implements all PowerPC instructions. + * v0.0 (09.05.1998) phx + * File created. + */ + + +#ifndef PPC_DISASM_H +#define PPC_DISASM_H + +#define PPC_GEKKO + +/* version/revision */ +#define PPCDISASM_VER 1 +#define PPCDISASM_REV 4 + + +/* typedefs */ +typedef unsigned int ppc_word; +#ifndef NULL +#define NULL (0L) +#endif + + +/* endianess */ +#define LITTLEENDIAN +#endif + +#if !defined(BIGENDIAN) && !defined(LITTLEENDIAN) +#error Define either BIGENDIAN or LITTLEENDIAN! +#define LITTLEENDIAN +#endif + + +/* 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) + + +#ifdef PPC_GEKKO + #define GEKKOLASMASK 0x0000007e + #define GEKKOWMASK 0x00000400 + #define GEKKOIMASK 0x00000380 + #define GEKKOW2MASK 0x00008000 + #define GEKKOI2MASK 0x00007000 + #define GEKKOVMASK 0x00000FFF + + #define GEKKOLASSH 1 + #define GEKKOWSH 10 + #define GEKKOISH 7 + #define GEKKOW2SH 15 + #define GEKKOI2SH 12 + #define GEKKOVSH 0 + + #define GEKKOGETLASID(x) (((x)&GEKKOLASMASK)>>GEKKOLASSH) + #define GEKKOGETW(x) (((x)&GEKKOWMASK)>>GEKKOWSH) + #define GEKKOGETI(x) (((x)&GEKKOIMASK)>>GEKKOISH) + #define GEKKOGETW2(x) (((x)&GEKKOW2MASK)>>GEKKOW2SH) + #define GEKKOGETI2(x) (((x)&GEKKOI2MASK)>>GEKKOI2SH) + #define GEKKOGETV(x) (((x)&GEKKOVMASK)>>GEKKOVSH) +#endif + +/* 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 */ +#define PPCF_ALTIVEC (1<<4) /* AltiVec instruction */ + + +/* ppc_disasm.o prototypes */ +#ifndef PPC_DISASM_C +extern ppc_word *PPC_Disassemble(struct DisasmPara_PPC *); +#endif + + diff --git a/symbolizer/symbolizer.pro b/symbolizer/symbolizer.pro index fd6ab44..77cd832 100644 --- a/symbolizer/symbolizer.pro +++ b/symbolizer/symbolizer.pro @@ -19,10 +19,12 @@ SOURCES += main.cpp\ ../WiiQt/aes.c \ elfparser.cpp \ dol.cpp \ - be.cpp + be.cpp \ + ppc_disasm.c HEADERS += ../WiiQt/tools.h \ ../WiiQt/aes.h \ elfparser.h \ dol.h \ - be.h + be.h \ + ppc_disasm.h