--- a
+++ b/ppcd.cpp
@@ -0,0 +1,1770 @@
+// Very accurate PowerPC Architecture disassembler (both 32 and 64-bit instructions are supported)
+
+// Branch Target in output parameters is NOT relative. Its already precalculated
+// from effective address of current instruction.
+
+// Note, that old mnemonics and operands will be overwritten, after next disasm
+// call. So dont forget to copy them away, if supposed to use them lately.
+
+// Instruction class can be combined from many flags. There can exist, for example,
+// "FPU" + "LDST" instruction, except "ILLEGAL", which cannot be combined.
+
+// RLWINM-like instructions mask is placed in output "target" parameter.
+
+#include <stdio.h>
+#include <string.h>
+
+#include "Commondefs.h"
+#include "ppcd.h"
+
+//efine POWERPC_32      // Use generic 32-bit model
+#define POWERPC_64      // Use generic 64-bit model
+//efine GEKKO           // Use Gekko (32-bit ISA)
+//efine BROADWAY        // Use Broadway (32-bit ISA)
+
+#define SIMPLIFIED      // Allow simplified mnemonics
+//efine UPPERCASE       // Use upper case strings in output
+#define COMMA   ", "
+#define LPAREN  " ("
+#define RPAREN  ")"
+#define HEX1    "0x"    // prefix
+#define HEX2    ""      // suffix
+
+static int bigendian = -1;  // Autodetect.
+
+// ---------------------------------------------------------------------------
+// Implementation. Look away, code is messed :)
+// Dont miss 'l' and '1'.
+
+static PPCD_CB *o;
+#define Instr   (o->instr)
+#define DIS_PC  (o->pc)
+
+// Simple decoder
+#define DIS_RD      ((Instr >> 21) & 0x1f)
+#define DIS_RS      DIS_RD
+#define DIS_RA      ((Instr >> 16) & 0x1f)
+#define DIS_RB      ((Instr >> 11) & 0x1f)
+#define DIS_RC      ((Instr >>  6) & 0x1f)
+#define DIS_RE      ((Instr >>  1) & 0x1f)
+#define DIS_MB      DIS_RC
+#define DIS_ME      DIS_RE
+#define DIS_OE      (Instr & 0x400)
+#define DIS_SIMM    ((s16)Instr)
+#define DIS_UIMM    (Instr & 0xffff)
+#define DIS_CRM     ((Instr >> 12) & 0xff)
+#define AA          (Instr & 2)
+#define LK          (Instr & 1)
+#define AALK        (Instr & 3)
+#define Rc          LK
+
+// GPRs. sp, sd1 and sd2 are named corresponding to PPC EABI.
+static char *regname[] = {
+#ifdef UPPERCASE
+ "R0" , "SP" , "SD2", "R3" , "R4" , "R5" , "R6" , "R7" , 
+ "R8" , "R9" , "R10", "R11", "R12", "SD1", "R14", "R15", 
+ "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 
+ "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31"
+#else
+ "r0" , "sp" , "sd2", "r3" , "r4" , "r5" , "r6" , "r7" , 
+ "r8" , "r9" , "r10", "r11", "r12", "sd1", "r14", "r15", 
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+#endif
+};
+#define REGD        (regname[DIS_RD])
+#define REGS        (regname[DIS_RS])
+#define REGA        (regname[DIS_RA])
+#define REGB        (regname[DIS_RB])
+
+// Illegal instruction.
+static void ill(void)
+{
+#if 1
+    o->mnemonic[0] = o->operands[0] = '\0';
+#else
+    strcpy(o->mnemonic, ".word");
+    sprintf(o->operands, HEX1 "%08X" HEX2, Instr);
+#endif
+    o->iclass = PPC_DISA_ILLEGAL;
+}
+
+// Smart SIMM formatting (if hex=1, then force HEX; if s=1, use sign)
+static char * simm(int val, int hex, int s)
+{
+    static char out[16];
+    if( ((val >= -256) && (val <= 256)) && !hex) sprintf(out, "%i", val);
+    else
+    {
+        u16 hexval = (u16)val;
+        if((hexval & 0x8000) && s) sprintf(out, "-" HEX1 "%04X" HEX2, ((~hexval) & 0xffff) + 1);
+        else sprintf(out, HEX1 "%04X" HEX2, hexval);
+    }
+    return out;
+}
+
+// Simple instruction form + reserved bitmask.
+static void put(char * mnem, u32 mask, u32 chkval=0, int iclass=PPC_DISA_OTHER)
+{
+    if( (Instr & mask) != chkval ) { ill(); return; }
+    o->iclass |= iclass;
+    strncpy(o->mnemonic, mnem, sizeof(o->mnemonic));
+}
+
+// Simplified mnemonic trap conditions
+static char * t_cond[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,
+};
+
+// Trap instructions.
+static void trap(int L, int imm)
+{
+    static char t_mode[2] = { 'w', 'd' };
+    int rd = DIS_RD;    // TO
+    int s = (rd & 0x18) ? 1 : 0;
+#ifdef  SIMPLIFIED
+    if(t_cond[rd] != NULL)
+    {
+        sprintf(o->mnemonic, "t%c%s%c", t_mode[L & 1], t_cond[rd], imm ? 'i' : 0);
+        if(imm) sprintf(o->operands, "%s" COMMA "%s", REGA, simm(DIS_SIMM, 0, s));
+        else sprintf(o->operands, "%s" COMMA "%s", REGA, REGB);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+    }
+    else
+#endif
+    {
+        sprintf(o->mnemonic, "t%c%c", t_mode[L & 1], imm ? 'i' : 0);
+        if(imm) sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, simm(DIS_SIMM, 0, s));
+        else sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, REGB);
+    }
+    if(L) o->iclass |= PPC_DISA_64;
+    o->r[1] = DIS_RA; if(!imm) o->r[2] = DIS_RB;
+    if(imm)
+    {
+        o->immed = Instr & 0xFFFF;
+        if(o->immed & 0x8000) o->immed |= 0xFFFF0000;
+    }
+}
+
+// DAB mask
+#define DAB_D   4
+#define DAB_A   2
+#define DAB_B   1
+
+// ASB mask
+#define ASB_A   4
+#define ASB_S   2
+#define ASB_B   1
+
+// cr%i 
+#ifdef UPPERCASE
+    static char crname[] = "CR";
+#else
+    static char crname[] = "cr";
+#endif
+
+// fr%i
+#ifdef UPPERCASE
+    static char fregname[] = "FR";
+#else
+    static char fregname[] = "fr";
+#endif
+
+// Integer instructions
+// form: 'D'    rD, rA, (s)IMM
+//       'S'    rA, rS, (s)IMM
+//       'X'    rD, rA, rB
+//       'Z'    rA, rS, rB
+//       'F'    frD, rA, rB
+// dab LSB bits : [D][A][B] (D should always present)
+// 'hex' for logic opcodes, 's' for alu opcodes, 'crfD' and 'L' for cmp opcodes
+// 'imm': 1 to show immediate operand
+static void integer(char *mnem, char form, int dab, int hex=0, int s=1, int crfD=0, int L=0, int imm=1)
+{
+    char * ptr = o->operands;
+    int rd = DIS_RD, ra = DIS_RA, rb = DIS_RB;
+    strncpy(o->mnemonic, mnem, sizeof(o->mnemonic));
+    if(crfD) ptr += sprintf(ptr, "%s%i" COMMA, crname, rd >> 2); // CMP only
+    if(L) ptr += sprintf(ptr, "%i" COMMA, rd & 1);           // CMP only
+    if(form == 'D')
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s));
+    }
+    else if(form == 'S')
+    {
+        if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA);
+        if(dab & ASB_S)
+        {
+            if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGS);
+        }
+        if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s));
+    }
+    else if(form == 'X')    // DAB
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(dab & DAB_B)
+        {
+            if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else if(form == 'F')    // FPU DAB
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s%i", fregname, rd);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(dab & DAB_B)
+        {
+            if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else if(form == 'Z')    // ASB
+    {
+        if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA);
+        if(dab & ASB_S)
+        {
+            if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGS);
+        }
+        if(dab & ASB_B)
+        {
+            if(dab & (ASB_A|ASB_S)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else { ill(); return; }
+    if(form == 'D' || form == 'X' || form == 'F') { o->r[0] = rd; o->r[1] = ra; }
+    if(form == 'S' || form == 'Z') { o->r[0] = ra; o->r[1] = rd; }
+    if(form == 'X' || form == 'Z' || form == 'F') o->r[2] = rb;
+    if((form == 'D' || form == 'S') && imm)
+    {
+        o->immed = Instr & 0xFFFF;
+        if(o->immed & 0x8000 && s) o->immed |= 0xFFFF0000;
+    }
+    o->iclass |= PPC_DISA_INTEGER;
+}
+
+// Compare instructions (wraps to integer call)
+static void cmp(char *l, char *i)
+{
+    char mnem[sizeof(o->mnemonic)];
+    int rd = DIS_RD;
+    
+    if(rd & 2) { ill(); return; }   // Reserved bit set
+    if(rd & 1)
+    {
+#ifndef  POWERPC_64
+        { ill(); return; }
+#endif
+        o->iclass |= PPC_DISA_64;
+    }
+
+#ifdef  SIMPLIFIED
+    sprintf(mnem, "cmp%s%c%s", l, (rd & 1) ? 'd' : 'w', i);
+    integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, (rd >> 2) ? 1 : 0, 0);
+    o->iclass |= PPC_DISA_SIMPLIFIED;
+#else
+    sprintf(mnem, "cmp%s%s", l, i);
+    integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, 1, 1);
+#endif
+}
+
+// Add immediate (wraps to integer call)
+static void addi(char *suffix)
+{
+    char mnem[sizeof(o->mnemonic)];
+
+#ifdef  SIMPLIFIED
+    if( (suffix[0] == '\0') && (DIS_RA == 0) )  // Load immediate
+    {
+        integer("li", 'D', DAB_D, 0, 1);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+        return;
+    }
+    if( (suffix[0] == 's') && (DIS_RA == 0) )   // Load address HI
+    {
+        integer("lis", 'D', DAB_D, 1, 0);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+        return;
+    }
+    if(DIS_UIMM & 0x8000)
+    {
+        sprintf(mnem, "subi%s", suffix);
+
+        // Fix immediate field.
+        u16 value = (u16)(~(DIS_UIMM) + 1);
+        Instr = (Instr & ~0xFFFF) | value;
+
+        integer(mnem, 'D', DAB_D|DAB_A, 0, 1);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+    }
+    else
+    {
+        sprintf(mnem, "addi%s", suffix);
+        integer(mnem, 'D', DAB_D|DAB_A, 0, 0);
+    }
+#else
+    sprintf(mnem, "addi%s", suffix);
+    integer(mnem, 'D', DAB_D|DAB_A);
+#endif
+}
+
+// Branch suffix: AA || LK.
+static char *b_opt[4] = { "", "l", "a", "la" };
+
+// Branch condition code: 4 * BO[1] + (BI & 3)
+static char * b_cond[8] = {
+ "ge", "le", "ne", "ns", "lt", "gt", "eq", "so"
+};
+
+// Branch on CTR code: BO[0..3]
+static char * b_ctr[16] = {
+ "dnzf", "dzf", NULL, NULL, "dnzt", "dzt", NULL, NULL,
+ "dnz", "dz", NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+// Place target address in operands. Helper for bcx/bx calls.
+static char *place_target(char *ptr, int comma)
+{
+    char *old;
+    u32 *t = (u32 *)&o->target;
+
+    if(comma) ptr += sprintf(ptr, "%s", COMMA);
+    old = ptr;
+#ifdef  POWERPC_32
+    ptr += sprintf(ptr, HEX1 "%08X" HEX2, (u32)o->target);
+#endif
+#ifdef  POWERPC_64
+    ptr = old;
+    if(bigendian) ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[0], t[1]);
+    else ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[1], t[0]);
+#endif
+    return ptr;
+}
+
+// Branch conditional.
+// Disp:1 - branch with displacement..
+// Disp:0 - branch by register (L:1 for LR, L:0 for CTR).
+static void bcx(int Disp, int L)
+{
+    u64 bd = 0;
+    int bo = DIS_RD, bi = DIS_RA;
+    char *r = Disp ? "" : (L ? "lr" : "ctr");
+    char *ptr = o->operands;
+
+    if( DIS_RB && !Disp ) { ill(); return; }
+
+    o->operands[0] = '\0';
+    o->target = 0;
+    o->iclass |= PPC_DISA_BRANCH;
+
+    // Calculate displacement and target address
+    if(Disp)
+    {
+        bd = DIS_UIMM & ~3;
+        if(bd & 0x8000) bd |= 0xffffffffffff0000;
+        o->target = (AA ? 0 : DIS_PC) + bd;
+    }
+    else o->target = 0;
+
+    // Calculate branch prediction hint
+    char y = (bo & 1) ^ ((((s64)bd < 0) && Disp) ? 1 : 0);
+    y = y ? '+' : '-';
+
+    if(bo & 4)              // No CTR decrement                         // BO[2]
+    {
+        if(bo & 16)         // Branch always                            // BO[0]
+        {
+#ifdef  SIMPLIFIED
+            sprintf(o->mnemonic, "b%s%s", r, b_opt[Disp ? AALK : LK]);
+            if(Disp) ptr = place_target(ptr, 0);
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+#endif  // SIMPLIFIED
+        }
+        else                // Branch conditional
+        {
+            if(bo & 2) { ill(); return; }                               // BO[3]
+#ifdef  SIMPLIFIED
+            char *cond = b_cond[((bo & 8) >> 1) | (bi & 3)];
+            if(cond != NULL)                                            // BO[1]
+            {
+                sprintf(o->mnemonic, "b%s%s%s%c", cond, r, b_opt[Disp ? AALK : LK], y);
+                if(bi >= 4) ptr += sprintf(ptr, "%s%i", crname, bi >> 2);
+                if(Disp) ptr = place_target(ptr, bi >= 4);
+                o->iclass |= PPC_DISA_SIMPLIFIED;
+                return;
+            }
+#endif  // SIMPLIFIED
+        }
+    }
+    else                    // Decrement CTR
+    {
+        if(!L && !Disp) { ill(); return; }
+        if(bo & 8) { ill(); return; }                               // BO[1]
+#ifdef  SIMPLIFIED
+        if(b_ctr[bo >> 1])
+        {
+            sprintf(o->mnemonic, "b%s%s%s%c", b_ctr[bo >> 1], r, b_opt[Disp ? AALK : LK], y);
+            if(!(bo & 16)) ptr += sprintf(ptr, "%i", bi);
+            if(Disp) ptr = place_target(ptr, !(bo & 16));
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+#endif  // SIMPLIFIED
+    }
+
+    // Not simplified standard form
+    sprintf(o->mnemonic, "bc%s%s", r, b_opt[Disp ? AALK : LK]);
+    ptr += sprintf(ptr, "%i" COMMA "%i", bo, bi);
+    if(Disp) ptr = place_target(ptr, 1);
+}
+
+// Branch unconditional
+static void bx(void)
+{
+    // Calculate displacement and target address
+    u64 bd = Instr & 0x03fffffc;
+    if(bd & 0x02000000) bd |= 0xfffffffffc000000;
+    o->target = (AA ? 0 : DIS_PC) + bd;
+ 
+    o->iclass |= PPC_DISA_BRANCH;
+    sprintf(o->mnemonic, "b%s", b_opt[AALK]);
+    place_target(o->operands, 0);
+}
+
+// Move CR field
+static void mcrf(void)
+{
+    if(Instr & 0x63f801) { ill(); return; }
+    strncpy(o->mnemonic, "mcrf", sizeof(o->mnemonic));
+    sprintf(o->operands, "%s%i" COMMA "%s%i", crname, DIS_RD >> 2, crname, DIS_RA >> 2);
+}
+
+// CR logic operations
+static void crop(char *name, char *simp="", int ddd=0, int daa=0)
+{
+    if(Instr & 1) { ill(); return; }
+
+    int crfD = DIS_RD, crfA = DIS_RA, crfB = DIS_RB;
+
+#ifdef  SIMPLIFIED
+    if( crfA == crfB )
+    {
+        if( (crfD == crfA) && ddd )
+        {
+            sprintf(o->mnemonic, "cr%s", simp);
+            sprintf(o->operands, "%i", crfD);
+            o->r[0] = crfD;
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+        if( daa )
+        {
+            sprintf(o->mnemonic, "cr%s", simp);
+            sprintf(o->operands, "%i" COMMA "%i", crfD, crfA);
+            o->r[0] = crfD; o->r[1] = crfA;
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+    }
+#endif
+    sprintf(o->mnemonic, "cr%s", name);
+    sprintf(o->operands, "%i" COMMA "%i" COMMA "%i", crfD, crfA, crfB);
+    o->r[0] = crfD; o->r[1] = crfA; o->r[2] = crfB;
+}
+
+#define MASK32(b, e) \
+{ \
+    u32 mask = ((u32)0xffffffff >> (b)) ^ (((e) >= 31) ? 0 : ((u32)0xffffffff) >> ((e) + 1)); \
+    o->target = ((b) > (e)) ? (~mask) : (mask); \
+}
+
+#define MASK64(b, e) \
+{ \
+    u64 mask = ((u64)0xffffffffffffffff >> (b)) ^ (((e) >= 63) ? 0 : ((u64)0xffffffffffffffff) >> ((e) + 1)); \
+    o->target = ((b) > (e)) ? (~mask) : (mask); \
+}
+
+// Rotate left word.
+static void rlw(char *name, int rb, int ins=0)
+{
+    int mb = DIS_MB, me = DIS_ME;
+    char * ptr = o->operands;
+    sprintf(o->mnemonic, "rlw%s%c", name, Rc ? '.' : '\0');
+    ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS);
+    if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB);
+    else   ptr += sprintf(ptr, "%i" COMMA, DIS_RB);     // sh
+    ptr += sprintf(ptr, "%i" COMMA "%i", mb, me);
+
+    // Put mask in target.
+    MASK32(mb, me);
+#ifdef POWERPC_64
+    MASK64(mb+32, me+32);
+#endif
+
+    o->r[0] = DIS_RA;
+    o->r[1] = DIS_RS;
+    if(rb) o->r[2] = DIS_RB;
+    o->iclass |= PPC_DISA_INTEGER;
+}
+
+// RLD mask
+#define RLDM_LEFT       0       // MASK(b, 63)
+#define RLDM_RIGHT      1       // MASK(0, e)
+#define RLDM_INS        2       // MASK(b, ~n)
+
+// Rotate left double-word.
+static void rld(char *name, int rb, int mtype)
+{
+#ifdef POWERPC_64
+    int m = DIS_MB, n = DIS_RB;
+    if(Instr & 0x20) m += 32;   // b or e
+    if(Instr & 0x02) n += 32;   // sh
+
+    char * ptr = o->operands;
+    sprintf(o->mnemonic, "rld%s%c", name, Rc ? '.' : '\0');
+    ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS);
+    if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB);
+    else   ptr += sprintf(ptr, "%i" COMMA, n);
+    ptr += sprintf(ptr, "%i", m);
+
+    // Put mask in target.
+    switch(mtype)
+    {
+        case RLDM_LEFT: MASK64(m, 63); break;
+        case RLDM_RIGHT: MASK64(0, m); break;
+        case RLDM_INS: MASK64(m, ~n); break;
+    }
+
+    o->r[0] = DIS_RA;
+    o->r[1] = DIS_RS;
+    if(rb) o->r[2] = DIS_RB;
+    o->iclass |= PPC_DISA_64 | PPC_DISA_INTEGER;
+#endif
+}
+
+// Load/Store.
+static void ldst(char *name, int x/*indexed*/, int load=1, int L=0, int string=0, int fload=0)
+{
+    if(x) integer(name, fload ? 'F' : 'X', DAB_D|DAB_A|DAB_B);
+    else
+    {
+        int rd = DIS_RD, ra = DIS_RA;
+        s16 imm = DIS_SIMM;
+        strcpy (o->mnemonic, name);
+        sprintf (o->operands, "%s" COMMA "%s" LPAREN "%s" RPAREN, regname[rd], simm(imm, 0, 1), regname[ra]);
+        o->r[0] = rd;
+        o->r[1] = ra;
+        o->immed = DIS_UIMM & 0x8000 ? DIS_UIMM | 0xFFFF0000 : DIS_UIMM;
+    }
+
+    o->iclass = PPC_DISA_LDST;
+    if(L) o->iclass |= PPC_DISA_64;
+    if(string) o->iclass |= PPC_DISA_STRING;
+    if(fload) o->iclass |= PPC_DISA_FPU;
+}
+
+// Cache.
+static void cache(char *name, int flag=PPC_DISA_OTHER)
+{
+    if (DIS_RD) { ill(); return; }
+    else
+    {
+        integer(name, 'X', DAB_A|DAB_B);
+        o->r[0] = o->r[1];
+        o->r[1] = o->r[2];
+        o->r[2] = 0;
+        o->iclass &= ~PPC_DISA_INTEGER;
+        o->iclass |= flag;
+    }
+}
+
+static void movesr(char *name, int from, int L, int xform)
+{
+    int reg = DIS_RD, sreg = DIS_RA & 0xF, regb = DIS_RB;
+
+    strncpy(o->mnemonic, name, sizeof(o->mnemonic));
+    if(xform)
+    {
+        if(Instr & 0x001F0001) { ill(); return; }
+        sprintf(o->operands, "%s" COMMA "%s", regname[reg], regname[regb]);
+        o->r[0] = reg;
+        o->r[1] = regb;
+    }
+    else
+    {
+        if(Instr & 0x0010F801) { ill(); return; }
+        if(from)
+        {
+            sprintf(o->operands, "%s" COMMA "%i", regname[reg], sreg);
+            o->r[0] = reg;
+            o->r[1] = sreg;
+        }
+        else
+        {
+            sprintf(o->operands, "%i" COMMA "%s", sreg, regname[reg]);
+            o->r[0] = sreg;
+            o->r[1] = reg;
+        }
+    }
+
+    if(L) o->iclass |= PPC_DISA_OEA | PPC_DISA_OPTIONAL | PPC_DISA_BRIDGE | PPC_DISA_64;
+    else o->iclass |= PPC_DISA_OEA | PPC_DISA_BRIDGE;
+}
+
+static void mtcrf(void)
+{
+    int rs = DIS_RS, crm = DIS_CRM;
+
+#ifdef SIMPLIFIED
+    if(crm == 0xFF)
+    {
+        strncpy(o->mnemonic, "mtcr", sizeof(o->mnemonic));
+        sprintf(o->operands, "%s", regname[rs]);
+    }
+    else
+#endif
+    {
+        strncpy(o->mnemonic, "mtcrf", sizeof(o->mnemonic));
+        sprintf(o->operands, HEX1 "%02X" HEX2 COMMA "%s", crm, regname[rs]);
+    }
+    o->r[0] = rs;
+}
+
+static void mcrxr(void)
+{
+    if (Instr & 0x007FF800) { ill(); return; }
+    strcpy (o->mnemonic, "mcrxr");
+    sprintf (o->operands, "%s%i", crname, DIS_RD >> 2);
+    o->r[0] = DIS_RD >> 2;
+}
+
+static char *spr_name(int n)
+{
+    static char def[8];
+
+    switch(n)
+    {
+        // General architecture special-purpose registers.
+        case 1: return "XER";
+        case 8: return "LR";
+        case 9: return "CTR";
+        case 18: return "DSISR";
+        case 19: return "DAR";
+        case 22: return "DEC";
+        case 25: return "SDR1";
+        case 26: return "SRR0";
+        case 27: return "SRR1";
+        case 272: return "SPRG0";
+        case 273: return "SPRG1";
+        case 274: return "SPRG2";
+        case 275: return "SPRG3";
+#ifdef  POWERPC_64
+        case 280: return "ASR";
+#endif
+        case 284: return "TBL";
+        case 285: return "TBU";
+        case 287: return "PVR";
+        case 528: return "IBAT0U";
+        case 529: return "IBAT0L";
+        case 530: return "IBAT1U";
+        case 531: return "IBAT1L";
+        case 532: return "IBAT2U";
+        case 533: return "IBAT2L";
+        case 534: return "IBAT3U";
+        case 535: return "IBAT3L";
+        case 536: return "DBAT0U";
+        case 537: return "DBAT0L";
+        case 538: return "DBAT1U";
+        case 539: return "DBAT1L";
+        case 540: return "DBAT2U";
+        case 541: return "DBAT2L";
+        case 542: return "DBAT3U";
+        case 543: return "DBAT3L";
+
+        // Optional registers.
+#if !defined(GEKKO) && !defined(BROADWAY)
+        case 282: return "EAR";
+        case 1013: return "DABR";
+        case 1022: return "FPECR";
+        case 1023: return "PIR";
+#endif
+
+        // Gekko-specific SPRs
+#ifdef GEKKO
+        case 282: return "EAR";
+        case 912: return "GQR0";
+        case 913: return "GQR1";
+        case 914: return "GQR2";
+        case 915: return "GQR3";
+        case 916: return "GQR4";
+        case 917: return "GQR5";
+        case 918: return "GQR6";
+        case 919: return "GQR7";
+        case 920: return "HID2";
+        case 921: return "WPAR";
+        case 922: return "DMAU";
+        case 923: return "DMAL";
+        case 936: return "UMMCR0";
+        case 940: return "UMMCR1";
+        case 937: return "UPMC1";
+        case 938: return "UPMC2";
+        case 939: return "USIA";
+        case 941: return "UPMC3";
+        case 942: return "UPMC4";
+        case 943: return "USDA";
+        case 952: return "MMCR0";
+        case 953: return "PMC1";
+        case 954: return "PMC2";
+        case 955: return "SIA";
+        case 956: return "MMCR1";
+        case 957: return "PMC3";
+        case 958: return "PMC4";
+        case 959: return "SDA";
+        case 1008: return "HID0";
+        case 1009: return "HID1";
+        case 1010: return "IABR";
+        case 1013: return "DABR";
+        case 1017: return "L2CR";
+        case 1019: return "ICTC";
+        case 1020: return "THRM1";
+        case 1021: return "THRM2";
+        case 1022: return "THRM3";
+#endif
+    }
+
+    sprintf(def, "%u", n);
+    return def;
+}
+
+static char *tbr_name(int n)
+{
+    static char def[8];
+
+    switch(n)
+    {
+        // General architecture time-base registers.
+        case 268: return "TBL";
+        case 269: return "TBU";
+    }
+
+    sprintf(def, "%u", n);
+    return def;
+}
+
+static void movespr(int from)
+{
+    int spr = (DIS_RB << 5) | DIS_RA, f = 1;
+    char *fix;
+
+    if( !((spr == 1) || (spr == 8) || (spr == 9)) ) o->iclass |= PPC_DISA_OEA;
+
+    // Handle simplified mnemonic
+    if (spr == 1) { fix = "xer"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (spr == 8) { fix = "lr"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (spr == 9) { fix = "ctr"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else { fix = "spr"; f = 0; }
+
+    // Mnemonics and operands.
+    sprintf (o->mnemonic, "m%c%s", from ? 'f' : 't', fix);
+    if (f)
+    {
+        sprintf (o->operands, "%s", regname[DIS_RD]);
+        o->r[0] = DIS_RD;
+    }
+    else
+    {
+        if (from)
+        {
+            sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], spr_name(spr));
+            o->r[0] = DIS_RD;
+            o->r[1] = spr;
+        }
+        else
+        {
+            sprintf (o->operands, "%s" COMMA "%s", spr_name(spr), regname[DIS_RD]);
+            o->r[0] = spr;
+            o->r[1] = DIS_RD;
+        }
+    }
+}
+
+static void movetbr(void)
+{
+    int tbr = (DIS_RB << 5) | DIS_RA, f = 1;
+    char *fix;
+
+    // Handle simplified mnemonic
+    if (tbr == 268) { fix = "tbl"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (tbr == 269) { fix = "tbu"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else { fix = "tb"; f = 0; }
+
+    // Mnemonics and operands.
+    sprintf (o->mnemonic, "mf%s", fix);
+    if (f)
+    {
+        sprintf (o->operands, "%s", regname[DIS_RD]);
+        o->r[0] = DIS_RD;
+    }
+    else
+    {
+        sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], tbr_name(tbr));
+        o->r[0] = DIS_RD;
+        o->r[1] = tbr;
+    }
+}
+
+static void srawi(void)
+{
+    int rs = DIS_RS, ra = DIS_RA, sh = DIS_RB;
+    sprintf (o->mnemonic, "srawi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh);
+    o->r[0] = ra;
+    o->r[1] = rs;
+    o->r[2] = sh;
+    o->iclass = PPC_DISA_INTEGER;
+}
+
+static void sradi(void)
+{
+    int rs = DIS_RS, ra = DIS_RA, sh = (((Instr >> 1) & 1) << 5) | DIS_RB;
+    sprintf (o->mnemonic, "sradi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh);
+    o->r[0] = ra;
+    o->r[1] = rs;
+    o->r[2] = sh;
+    o->iclass = PPC_DISA_INTEGER | PPC_DISA_64;
+}
+
+static void lsswi(char *name)
+{
+    int rd = DIS_RD, ra = DIS_RA, nb = DIS_RB;
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[rd], regname[ra], nb);
+    o->r[0] = rd;
+    o->r[1] = ra;
+    o->r[2] = nb;
+    o->iclass = PPC_DISA_LDST | PPC_DISA_STRING;
+}
+
+#define FPU_DAB     1
+#define FPU_DB      2
+#define FPU_DAC     3
+#define FPU_DACB    4
+#define FPU_D       5
+
+static void fpu(char *name, u32 mask, int type, int flag=PPC_DISA_OTHER)
+{
+    int d = DIS_RD, a = DIS_RA, c = DIS_RC, b = DIS_RB;
+
+    if(Instr & mask) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+
+    switch (type)
+    {
+        case FPU_DAB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b);
+            o->r[0] = d; o->r[1] = a; o->r[2] = b;
+            break;
+        case FPU_DB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b);
+            o->r[0] = d; o->r[1] = b;
+            break;
+        case FPU_DAC:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c);
+            o->r[0] = d; o->r[1] = a; o->r[2] = c;
+            break;
+        case FPU_DACB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b);
+            o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b;
+            break;
+        case FPU_D:
+            sprintf (o->operands, "%s%i", fregname, d);
+            o->r[0] = d;
+            break;
+    }
+    
+    o->iclass = PPC_DISA_FPU | flag;
+}
+
+static void fcmp(char *name)
+{
+    int crfd = DIS_RD >> 2, ra = DIS_RA, rb = DIS_RB;
+
+    if (Instr & 0x00600001) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%i" COMMA "%s%i" COMMA "%s%i", crfd, fregname, ra, fregname, rb);
+    o->r[0] = crfd; o->r[1] = ra; o->r[2] = rb;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsf(void)
+{
+    int fm = (Instr >> 17) & 0xFF, rb = DIS_RB;
+
+    if(Instr & 0x02010000) { ill(); return; }
+
+    sprintf (o->mnemonic, "mtfsf%c", Rc ? '.' : 0);
+    sprintf (o->operands, HEX1 "%02X" HEX2 COMMA "%s%i", fm, fregname, rb);
+    o->r[0] = fm; o->r[1] = rb;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsb(char *name)
+{
+    int crbd = DIS_RD;
+
+    if (Instr & 0x001FF800) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%i", crbd);
+    o->r[0] = crbd;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mcrfs(void)
+{
+    int crfD = DIS_RD >> 2, crfS = DIS_RA >> 2;
+
+    if (Instr & 0x0063F801) { ill(); return; }
+
+    strcpy (o->mnemonic, "mcrfs");
+    sprintf (o->operands, "%s%i" COMMA "%s%i", crname, crfD, crname, crfS);
+    o->r[0] = crfD; o->r[1] = crfS;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsfi(void)
+{
+    int crfD = DIS_RD >> 2, imm = DIS_RB >> 1;
+
+    if (Instr & 0x007F0800) { ill(); return; }
+
+    sprintf (o->mnemonic, "mtfsfi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s%i" COMMA "%i", crname, crfD, imm);
+    o->r[0] = crfD; o->r[1] = imm;
+    o->iclass = PPC_DISA_FPU;
+}
+
+/*
+ ***********************************************************************************
+ * Architecture-specific extensions: 
+ * Processor model: GEKKO
+ ***********************************************************************************
+*/
+
+#ifdef  GEKKO
+
+static void ps_cmpx(int n)
+{
+    static char *fix[] = { "u0", "o0", "u1", "o1" };
+    if(Instr & 0x00600001) { ill(); return; }
+    sprintf(o->mnemonic, "ps_cmp%s", fix[n]);
+    o->r[0] = DIS_RD>>2; o->r[1] = DIS_RA; o->r[2] = DIS_RB;
+    sprintf(o->operands, "%s%d" COMMA "%s%d" COMMA "%s%d", crname, o->r[0], fregname, o->r[1], fregname, o->r[2]);
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 
+}
+
+static char *ps_ldst_offs(unsigned long val)
+{
+    static char buf[8];
+
+    if(val == 0)
+    {
+        return "0";
+    }
+    else
+    {
+        if(val <= 128)
+        {
+            sprintf(buf, "%i", val);
+            return buf;
+        }
+
+        if(val & 0x800) sprintf(buf, "-" HEX1 "%03X" HEX2, ((~val) & 0xfff) + 1);
+        else sprintf(buf, HEX1 "%03X" HEX2, val);
+
+        return buf;
+    }
+}
+
+static void ps_ldst(char *fix)
+{
+  int s = DIS_RS, a = DIS_RA, d = (Instr & 0xfff);
+  sprintf(o->mnemonic, "psq_%s", fix);  
+  sprintf( o->operands, "%s%i" COMMA "%s" LPAREN "%s" RPAREN COMMA "%i" COMMA "%i",
+           fregname, s, ps_ldst_offs(d), regname[a], (Instr >> 15) & 1, (Instr >> 12) & 7 );
+  o->r[0] = s; o->r[1] = a; o->r[2] = DIS_RB >> 1;
+  o->immed = d & 0x800 ? d | 0xFFFFF000 : d;
+  o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC;
+}
+
+static void ps_ldstx(char *fix)
+{
+    int d = DIS_RD, a = DIS_RA, b = DIS_RB;
+    if(Instr & 1) { ill(); return; }
+    sprintf(o->mnemonic, "psq_%s", fix);
+    sprintf(o->operands, "%s%i" COMMA "%s" COMMA "%s" COMMA "%i" COMMA "%i", fregname, d, regname[a], regname[b], (Instr >> 10) & 1, (Instr >> 7) & 7);
+    o->r[0] = d; o->r[1] = a; o->r[2] = b; o->r[3] = DIS_RC >> 1;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC; 
+}
+
+static void ps_dacb(char *fix)
+{
+    int a = DIS_RA, b = DIS_RB, c = DIS_RC, d = DIS_RD;
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b);
+    o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b; 
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_dac(char *fix)
+{
+    int a = DIS_RA, c = DIS_RC, d = DIS_RD;
+    if(Instr & 0x0000F800) { ill(); return; }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c);
+    o->r[0] = d; o->r[1] = a; o->r[2] = c;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_dab(char *fix, int unmask=0)
+{
+    int d = DIS_RD, a = DIS_RA, b = DIS_RB;
+    if(Instr & 0x000007C0 && !unmask) { ill(); return; }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b);
+    o->r[0] = d; o->r[1] = a; o->r[2] = b;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_db(char *fix, int aonly=0)
+{
+    int d = DIS_RD, b = DIS_RB;
+    if(aonly) { if(Instr & 0x001F0000) { ill(); return; } }
+    else  { if(Instr & 0x001F07C0) { ill(); return; } }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b);
+    o->r[0] = d; o->r[1] = b;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+#endif  /* END OF GEKKO */
+
+// ---------------------------------------------------------------------------
+
+void PPCDisasm(PPCD_CB *discb)
+{
+    // Save parameters in local variables for static calls
+    o = discb;
+    if(o == NULL) return;
+
+    // Detect endianness order.
+    if(bigendian == -1)
+    {
+        u8 test_value[2] = { 0xAA, 0xBB };
+        u16 *value = (u16 *)test_value;
+        if(*value == 0xAABB) bigendian = 1;
+        else bigendian = 0;
+    }
+
+    // Reset output parameters
+    o->iclass = PPC_DISA_OTHER;
+    o->r[0] = o->r[1] = o->r[2] = o->r[3] = 0;
+    o->immed = 0;
+    o->target = 0;
+    o->mnemonic[0] = o->operands[0] = '\0';
+
+    // Lets go!
+
+    /*
+     * Main table
+    */
+
+    switch(Instr >> 26 /* Main opcode, base 8 */) {
+#ifdef POWERPC_64
+        case 002: trap(1, 1); break;                                        // tdi
+#endif
+        case 003: trap(0, 1); break;                                        // twi
+        case 007: integer("mulli", 'D', DAB_D|DAB_A); break;                // mulli
+        case 010: integer("subfic", 'D', DAB_D|DAB_A); break;               // subfic
+        case 012: cmp("l", "i"); break;                                     // cmpli
+        case 013: cmp("", "i"); break;                                      // cmpi
+        case 014: addi("c"); break;                                         // addic
+        case 015: addi("c."); break;                                        // addic.
+        case 016: addi(""); break;                                          // addi
+        case 017: addi("s"); break;                                         // addis
+        case 020: bcx(1, 0); break;                                         // bcx
+        case 021: put("sc", 0x03ffffff, 2); break;                          // sc
+        case 022: bx(); break;                                              // bx
+        case 024: rlw("imi", 0, 1); break;                                  // rlwimix
+        case 025: rlw("inm", 0); break;                                     // rlwinmx
+        case 027: rlw("nm", 1); break;                                      // rlwnmx
+        case 030:                                                           // ori
+#ifdef SIMPLIFIED
+                  if(Instr == 0x60000000) put("nop", 0, 0, PPC_DISA_INTEGER | PPC_DISA_SIMPLIFIED);
+                  else
+#endif
+                  integer("ori", 'S', ASB_A|ASB_S, 1, 0); break;
+        case 031: integer("oris", 'S', ASB_A|ASB_S, 1, 0); break;           // oris
+        case 032: integer("xori", 'S', ASB_A|ASB_S, 1, 0); break;           // xori
+        case 033: integer("xoris", 'S', ASB_A|ASB_S, 1, 0); break;          // xoris
+        case 034: integer("andi.", 'S', ASB_A|ASB_S, 1, 0); break;          // andi.
+        case 035: integer("andis.", 'S', ASB_A|ASB_S, 1, 0); break;         // andis.
+        case 040: ldst("lwz", 0, 1); break;                                 // lwz
+        case 041: ldst("lwzu", 0, 1); break;                                // lwzu
+        case 042: ldst("lbz", 0, 1); break;                                 // lbz
+        case 043: ldst("lbzu", 0, 1); break;                                // lbzu
+        case 044: ldst("stw", 0, 0); break;                                 // stw
+        case 045: ldst("stwu", 0, 0); break;                                // stwu
+        case 046: ldst("stb", 0, 0); break;                                 // stb
+        case 047: ldst("stbu", 0, 0); break;                                // stbu
+        case 050: ldst("lhz", 0, 1); break;                                 // lhz
+        case 051: ldst("lhzu", 0, 1); break;                                // lhzu
+        case 052: ldst("lha", 0, 1); break;                                 // lha
+        case 053: ldst("lhau", 0, 1); break;                                // lhau
+        case 054: ldst("sth", 0, 0); break;                                 // sth
+        case 055: ldst("sthu", 0, 0); break;                                // sthu
+        case 056: ldst("lmw", 0, 1, 0, 1); break;                           // lmw
+        case 057: ldst("stmw", 0, 0, 0, 1); break;                          // stmw
+        case 060: ldst("lfs", 0, 1, 0, 0, 1); break;                        // lfs
+        case 061: ldst("lfsu", 0, 1, 0, 0, 1); break;                       // lfsu
+        case 062: ldst("lfd", 0, 1, 0, 0, 1); break;                        // lfd
+        case 063: ldst("lfdu", 0, 1, 0, 0, 1); break;                       // lfdu
+        case 064: ldst("stfs", 0, 0, 0, 0, 1); break;                       // stfs
+        case 065: ldst("stfsu", 0, 0, 0, 0, 1); break;                      // stfsu
+        case 066: ldst("stfd", 0, 0, 0, 0, 1); break;                       // stfd
+        case 067: ldst("stfdu", 0, 0, 0, 0, 1); break;                      // stfdu
+
+    /*
+     * Extention 1.
+    */
+
+        case 023:
+    switch((Instr >> 1) & 0x3ff /* Extended opcode 023, base 8 */) {
+        case 00020: bcx(0, 1); break;                                       // bclrx
+        case 01020: bcx(0, 0); break;                                       // bcctrx
+        case 00000: mcrf(); break;                                          // mcrf
+        case 00401: crop("and"); break;                                     // crand
+        case 00201: crop("andc"); break;                                    // crandc
+        case 00441: crop("eqv", "set", 1); break;                           // creqv
+        case 00341: crop("nand"); break;                                    // crnand
+        case 00041: crop("nor", "not", 0, 1); break;                        // crnor
+        case 00701: crop("or", "move", 0, 1); break;                        // cror
+        case 00641: crop("orc"); break;                                     // crorc
+        case 00301: crop("xor", "clr", 1); break;                           // crxor
+        case 00226: put("isync", 0x3fff801); break;                         // isync
+#ifdef  POWERPC_32
+        case 00062: put("rfi", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_BRIDGE ); break; // rfi
+#endif
+#ifdef  POWERPC_64
+        case 00022: put("rfid", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_64 ); break; // rfid
+#endif
+        default: ill(); break;
+    } break;
+
+#ifdef  POWERPC_64
+        case 036:
+    switch((Instr >> 1) & 0xf /* Rotate left double */) {
+        case 0x0: rld("icl", 0, RLDM_LEFT); break;                          // rldiclx
+        case 0x1: rld("icl", 0, RLDM_LEFT); break;
+        case 0x2: rld("icr", 0, RLDM_RIGHT); break;                         // rldicrx
+        case 0x3: rld("icr", 0, RLDM_RIGHT); break;
+        case 0x4: rld("ic",  0, RLDM_INS); break;                           // rldicx
+        case 0x5: rld("ic",  0, RLDM_INS); break;
+        case 0x6: rld("imi", 0, RLDM_INS); break;                           // rldimix
+        case 0x7: rld("imi", 0, RLDM_INS); break;
+        case 0x8: rld("cl",  1, RLDM_LEFT); break;                          // rldclx
+        case 0x9: rld("cr",  1, RLDM_RIGHT); break;                         // rldcrx
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 2.
+    */
+
+        #define OE 02000
+        case 037:
+    switch(Instr & 0x7ff /* Extended opcode 037, base 8 */) {
+        case 00000: cmp("", ""); break;                                     // cmp
+        case 00010:                                                         // tw
+#ifdef SIMPLIFIED
+                    if(Instr == 0x7FE00008) put("trap", 0, 0, PPC_DISA_SIMPLIFIED);
+                    else
+#endif
+                    trap(0, 0); break;
+        case 00020: integer("subfc", 'X', DAB_D|DAB_A|DAB_B); break;        // subfcx
+        case 00020|OE: integer("subfco", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00021: integer("subfc.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00021|OE: integer("subfco.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00024: integer("addc", 'X', DAB_D|DAB_A|DAB_B); break;         // addcx
+        case 00024|OE: integer("addco", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00025: integer("addc.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00025|OE: integer("addco.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00026: integer("mulhwu", 'X', DAB_D|DAB_A|DAB_B); break;       // mulhwu
+        case 00027: integer("mulhwu.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00046: if(DIS_RA | DIS_RB) ill();                              // mfcr
+                    else { integer("mfcr", 'D', DAB_D, 0,0,0,0,0); o->iclass = PPC_DISA_OTHER; } break;
+        case 00050: ldst("lwarx", 1); break;                                // lwarx
+        case 00056: ldst("lwzx", 1); break;                                 // lwzx
+        case 00060: integer("slw", 'Z', ASB_A|ASB_S|ASB_B); break;          // slwx
+        case 00061: integer("slw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00064: if(DIS_RB) ill();                                       // cntlzwx
+                    else integer("cntlzw", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 00065: if(DIS_RB) ill();
+                    else integer("cntlzw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 00070: integer("and", 'Z', ASB_A|ASB_S|ASB_B); break;          // andx
+        case 00071: integer("and.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00100: cmp("l", ""); break;                                    // cmpl
+        case 00120: integer("subf", 'X', DAB_D|DAB_A|DAB_B); break;         // subfx
+        case 00120|OE: integer("subfo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00121: integer("subf.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00121|OE: integer("subfo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00154: cache("dcbst"); break;                                  // dcbst
+        case 00156: ldst("lwzux", 1); break;                                // lwzux
+        case 00170: integer("andc", 'Z', ASB_A|ASB_S|ASB_B); break;         // andcx
+        case 00171: integer("andc.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00226: integer("mulhw", 'X', DAB_D|DAB_A|DAB_B); break;        // mulhw
+        case 00227: integer("mulhw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00246: if(DIS_RA || DIS_RB) ill();                             // mfmsr
+                    else { integer("mfmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA; } break;
+        case 00254: cache("dcbf"); break;                                   // dcbf
+        case 00256: ldst("lbzx", 1, 1, 0); break;                           // lbzx
+        case 00320: if(DIS_RB) ill();                                       // negx
+                    else integer("neg", 'X', DAB_D|DAB_A); break;
+        case 00321: if(DIS_RB) ill();
+                    else integer("neg.", 'X', DAB_D|DAB_A); break;
+        case 00320|OE: if(DIS_RB) ill();
+                    else integer("nego", 'X', DAB_D|DAB_A); break;
+        case 00321|OE: if(DIS_RB) ill();
+                    else integer("nego.", 'X', DAB_D|DAB_A); break;
+        case 00356: ldst("lbzux", 1, 1); break;                             // lbzux
+        case 00370:                                                         // norx
+#ifdef SIMPLIFIED
+                    if(DIS_RS == DIS_RB) { integer("not", 'Z', ASB_A|ASB_S); o->iclass |= PPC_DISA_SIMPLIFIED; }
+                    else
+#endif
+                    integer("nor", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00371: integer("nor.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00420: integer("subfe", 'X', DAB_D|DAB_A|DAB_B); break;        // subfex
+        case 00420|OE: integer("subfeo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00421: integer("subfe.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00421|OE: integer("subfeo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00424: integer("adde", 'X', DAB_D|DAB_A|DAB_B); break;         // addex
+        case 00424|OE: integer("addeo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00425: integer("adde.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00425|OE: integer("addeo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00440: mtcrf(); break;                                         // mtcrf
+#ifdef POWERPC_32
+        case 00444: if(DIS_RA || DIS_RB) ill();                             // mtmsr
+                    else { integer("mtmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_BRIDGE; } break;
+#endif
+        case 00455: ldst("stwcx.", 1, 0, 0); break;                         // stwcx.
+        case 00456: ldst("stwx", 1, 0, 0); break;                           // stwx
+        case 00556: ldst("stwux", 1, 0, 0); break;                          // stwux
+        case 00620: if(DIS_RB) ill();                                       // subfzex
+                    else integer("subfze", 'X', DAB_D|DAB_A); break;
+        case 00620|OE: if(DIS_RB) ill();
+                    else integer("subfzeo", 'X', DAB_D|DAB_A); break;
+        case 00621: if(DIS_RB) ill();
+                    else integer("subfze.", 'X', DAB_D|DAB_A); break;
+        case 00621|OE: if(DIS_RB) ill();
+                    else integer("subfzeo.", 'X', DAB_D|DAB_A); break;
+        case 00624: if(DIS_RB) ill();                                       // addzex
+                    else integer("addze", 'X', DAB_D|DAB_A); break;
+        case 00624|OE: if(DIS_RB) ill();
+                    else integer("addzeo", 'X', DAB_D|DAB_A); break;
+        case 00625: if(DIS_RB) ill();
+                    else integer("addze.", 'X', DAB_D|DAB_A); break;
+        case 00625|OE: if(DIS_RB) ill();
+                    else integer("addzeo.", 'X', DAB_D|DAB_A); break;
+#ifdef POWERPC_32
+        case 00644: movesr("mtsr", 0, 0, 0); break;                         // mtsr
+#endif
+        case 00656: ldst("stbx", 1, 0, 0); break;                           // stbx
+        case 00720: if(DIS_RB) ill();                                       // subfmex
+                    else integer("subfme", 'X', DAB_D|DAB_A); break;
+        case 00720|OE: if(DIS_RB) ill();
+                    else integer("subfmeo", 'X', DAB_D|DAB_A); break;
+        case 00721: if(DIS_RB) ill();
+                    else integer("subfme.", 'X', DAB_D|DAB_A); break;
+        case 00721|OE: if(DIS_RB) ill();
+                    else integer("subfmeo.", 'X', DAB_D|DAB_A); break;
+        case 00724: if(DIS_RB) ill();                                       // addmex
+                    else integer("addme", 'X', DAB_D|DAB_A); break;
+        case 00724|OE: if(DIS_RB) ill();
+                    else integer("addmeo", 'X', DAB_D|DAB_A); break;
+        case 00725: if(DIS_RB) ill();
+                    else integer("addme.", 'X', DAB_D|DAB_A); break;
+        case 00725|OE: if(DIS_RB) ill();
+                    else integer("addmeo.", 'X', DAB_D|DAB_A); break;
+        case 00726: integer("mullw", 'X', DAB_D|DAB_A|DAB_B); break;        // mullwx
+        case 00726|OE: integer("mullwo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00727: integer("mullw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00727|OE: integer("mullwo.", 'X', DAB_D|DAB_A|DAB_B); break;
+#ifdef POWERPC_32
+        case 00744: movesr("mtsrin", 0, 0, 1); break;                       // mtsrin
+#endif
+        case 00754: cache("dcbtst"); break;                                 // dcbtst
+        case 00756: ldst("stbux", 1, 0, 0); break;                          // stbux
+        case 01024: integer("add", 'X', DAB_D|DAB_A|DAB_B); break;          // addx
+        case 01024|OE: integer("addo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01025: integer("add.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01025|OE: integer("addo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01054: cache("dcbt"); break;                                   // dcbt
+        case 01056: ldst("lhzx", 1); break;                                 // lhzx
+        case 01070: integer("eqv", 'Z', ASB_A|ASB_S|ASB_B); break;          // eqvx
+        case 01071: integer("eqv.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01144: if(DIS_RD || DIS_RA) ill();                             // tlbie
+                    else { integer("tlbie", 'X', DAB_B); o->iclass = PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break;
+        case 01154: integer("eciwx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // eciwx
+        case 01156: ldst("lhzux", 1); break;                                // lhzux
+        case 01170: integer("xor", 'Z', ASB_A|ASB_S|ASB_B); break;          // xorx
+        case 01171: integer("xor.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01246: movespr(1); break;                                      // mfspr
+        case 01256: ldst("lhax", 1); break;                                 // lhax
+#if !defined(GEKKO)
+        case 01344: put("tlbia", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbia
+#endif
+        case 01346: movetbr(); break;                                       // mftb
+        case 01356: ldst("lhaux", 1); break;                                // lhaux
+        case 01456: ldst("sthx", 1, 0); break;                              // sthx
+        case 01470: integer("orc", 'Z', ASB_A|ASB_S|ASB_B); break;          // orcx
+        case 01471: integer("orc.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01554: integer("ecowx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // ecowx
+        case 01556: ldst("sthux", 1, 0); break;                             // sthux
+        case 01570: integer("or", 'Z', ASB_A|ASB_S|ASB_B); break;           // orx
+        case 01571: integer("or.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01626: integer("divwu", 'X', DAB_D|DAB_A|DAB_B); break;        // divwux
+        case 01626|OE: integer("divwuo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01627: integer("divwu.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01627|OE: integer("divwuo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01646: movespr(0); break;                                      // mtspr
+        case 01654: cache("dcbi", PPC_DISA_OEA); break;                     // dcbi
+        case 01670: integer("nand", 'Z', ASB_A|ASB_S|ASB_B); break;         // nandx
+        case 01671: integer("nand.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01726: integer("divw", 'X', DAB_D|DAB_A|DAB_B); break;         // divwx
+        case 01726|OE: integer("divwo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01727: integer("divw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01727|OE: integer("divwo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 02000: mcrxr(); break;                                         // mcrxr
+        case 02052: ldst("lswx", 1, 1, 0, 1); break;                        // lswx
+        case 02054: ldst("lwbrx", 1); break;                                // lwbrx
+        case 02056: ldst("lfsx", 1, 1, 0, 0, 1); break;                     // lfsx
+        case 02060: integer("srw", 'Z', ASB_A|ASB_S|ASB_B); break;          // srwx
+        case 02061: integer("srw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 02154: put("tlbsync", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbsync
+        case 02156: ldst("lfsux", 1, 1, 0, 0, 1); break;                    // lfsux
+#ifdef POWERPC_32
+        case 02246: movesr("mfsr", 1, 0, 0); break;                         // mfsr
+#endif
+        case 02252: lsswi("lswi"); break;                                   // lswi
+        case 02254: put("sync", 0x03FFF800, 0); break;                      // sync
+        case 02256: ldst("lfdx", 1, 1, 0, 0, 1); break;                     // lfdx
+        case 02356: ldst("lfdux", 1, 1, 0, 0, 1); break;                    // lfdux
+#ifdef POWERPC_32
+        case 02446: movesr("mfsrin", 1, 0, 1); break;                       // mfsrin
+#endif
+        case 02452: ldst("stswx", 1, 1, 0, 1); break;                       // stswx
+        case 02454: ldst("stwbrx", 1, 0); break;                            // stwbrx
+        case 02456: ldst("stfsx", 1, 1, 0, 0, 1); break;                    // stfsx
+        case 02556: ldst("stfsux", 1, 1, 0, 0, 1); break;                   // stfsux
+        case 02652: lsswi("stswi"); break;                                  // stswi
+        case 02656: ldst("stfdx", 1, 1, 0, 0, 1); break;                    // stfdx
+#if !defined(GEKKO)
+        case 02754: cache("dcba", PPC_DISA_OPTIONAL); break;                // dcba
+#endif
+        case 02756: ldst("stfdux", 1, 1, 0, 0, 1); break;                   // stfdux
+        case 03054: ldst("lhbrx", 1); break;                                // lhbrx
+        case 03060: integer("sraw", 'Z', ASB_A|ASB_S|ASB_B); break;         // srawx
+        case 03061: integer("sraw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 03160: srawi(); break;                                         // srawi
+        case 03161: srawi(); break;
+        case 03254: put("eieio", 0x03FFF800, 0); break;                     // eieio
+        case 03454: ldst("sthbrx", 1, 0); break;                            // sthbrx
+        case 03464: if(DIS_RB) ill();                                       // extshx
+                    else integer("extsh", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03465: if(DIS_RB) ill();
+                    else integer("extsh.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03564: if(DIS_RB) ill();                                       // extsbx
+                    else integer("extsb", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03565: if(DIS_RB) ill();
+                    else integer("extsb.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03654: cache("icbi"); break;                                   // icbi
+        case 03656: ldst("stfiwx", 1, 1, 0, 0, 1); o->iclass |= PPC_DISA_OPTIONAL; break; // stfiwx
+        case 03754: cache("dcbz"); break;                                   // dcbz
+#ifdef POWERPC_64
+        case 00022: integer("mulhdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdux
+        case 00023: integer("mulhdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00052: ldst("ldx", 1, 1, 1); break;                            // ldx
+        case 00066: integer("sld", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sldx
+        case 00067: integer("sld.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 00152: ldst("ldux", 1, 1, 1); break;                           // ldux
+        case 00164: if(DIS_RB) ill();                                       // cntlzdx
+                    else integer("cntlzd", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+        case 00165: if(DIS_RB) ill();
+                    else integer("cntlzd.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+        case 00210: trap(1, 0); break;
+        case 00222: integer("mulhd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdx
+        case 00223: integer("mulhd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00244: movesr("mtsrd", 0, 1, 0); break;                        // mtrsd
+        case 00250: ldst("ldarx", 1, 1, 1); break;                          // ldarx
+        case 00344: movesr("mtsrdin", 0, 1, 1); break;                      // mtrsdin
+        case 00452: ldst("stdx", 1, 0, 1); break;                           // stdx
+        case 00544: if(DIS_RA || DIS_RB) ill();                             // mtmsrd
+                    else { integer("mtmsrd", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_64; } break;
+        case 00552: ldst("stdux", 1, 0, 1); break;                          // stdux
+        case 00655: ldst("stdcx.", 1, 0, 1); break;                         // stdcx.
+        case 00722: integer("mulld", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulldx
+        case 00722|OE: integer("mulldo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00723: integer("mulld.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00723|OE: integer("mulldo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01252: ldst("lwax", 1, 1, 1); break;                           // lwax
+        case 01352: ldst("lwaux", 1, 1, 1); break;                          // lwaux
+        case 03164: sradi(); break;                                         // sradi
+        case 03165: sradi(); break;
+        case 03166: sradi(); break;
+        case 03167: sradi(); break;
+        case 01544: if(DIS_RD || DIS_RA) ill();                             // slbie
+                    else { integer("slbie", 'X', DAB_B); o->iclass = PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break;
+        case 01622: integer("divdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdux
+        case 01622|OE: integer("divduo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01623: integer("divdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01623|OE: integer("divduo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01722: integer("divd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdx
+        case 01722|OE: integer("divdo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01723: integer("divd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01723|OE: integer("divdo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01744: put("slbia", 0x03FFF800, 0, PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // slbia
+        case 02066: integer("srd", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // srdx
+        case 02067: integer("srd.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 03064: integer("srad", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sradx
+        case 03065: integer("srad.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 03664: if(DIS_RB) ill();                                       // extswx
+                    else integer("extsw", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+        case 03665: if(DIS_RB) ill();
+                    else integer("extsw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+#endif
+        default: ill(); break;
+    } break;
+
+    /*
+     * Extention 3.
+    */
+
+#ifdef POWERPC_64
+        case 072:
+    switch(Instr & 3) {
+        case 0: Instr &= ~3; ldst("ld", 0, 1, 1); break;                    // ld
+        case 1: Instr &= ~3; ldst("ldu", 0, 1, 1); break;                   // ldu
+        case 2: Instr &= ~3; ldst("lwa", 0, 1, 1); break;                   // lwa
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 4.
+    */
+
+    #define MASK_D  (0x1F << 21)
+    #define MASK_A  (0x1F << 16)
+    #define MASK_B  (0x1F << 11)
+    #define MASK_C  (0x1F <<  6)
+        case 073:
+    switch(Instr & 0x3F) {
+        case 044: fpu("fdivs", MASK_C, FPU_DAB); break;                     // fdivsx
+        case 045: fpu("fdivs.", MASK_C, FPU_DAB); break;
+        case 050: fpu("fsubs", MASK_C, FPU_DAB); break;                     // fsubsx
+        case 051: fpu("fsubs.", MASK_C, FPU_DAB); break;
+        case 052: fpu("fadds", MASK_C, FPU_DAB); break;                     // faddsx
+        case 053: fpu("fadds.", MASK_C, FPU_DAB); break;
+#if !defined(GEKKO)
+        case 054: fpu("fsqrts", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtsx
+        case 055: fpu("fsqrts.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+#endif
+        case 060: fpu("fres", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fresx
+        case 061: fpu("fres.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+        case 062: fpu("fmuls", MASK_B, FPU_DAC); break;                     // fmulsx
+        case 063: fpu("fmuls.", MASK_B, FPU_DAC); break;
+        case 070: fpu("fmsubs", 0, FPU_DACB); break;                        // fmsubsx
+        case 071: fpu("fmsubs.", 0, FPU_DACB); break;
+        case 072: fpu("fmadds", 0, FPU_DACB); break;                        // fmaddsx
+        case 073: fpu("fmadds.", 0, FPU_DACB); break;
+        case 074: fpu("fnmsubs", 0, FPU_DACB); break;                       // fnmsubsx
+        case 075: fpu("fnmsubs.", 0, FPU_DACB); break;
+        case 076: fpu("fnmadds", 0, FPU_DACB); break;                       // fnmaddsx
+        case 077: fpu("fnmadds.", 0, FPU_DACB); break;
+        default: ill(); break;
+    } break;
+
+    /*
+     * Extention 5.
+    */
+
+#ifdef POWERPC_64
+        case 076:
+    switch(Instr & 3) {
+        case 0: Instr &= ~3; ldst("std", 0, 0, 1); break;                   // std
+        case 1: Instr &= ~3; ldst("stdu", 0, 0, 1); break;                  // stdu
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 6.
+    */
+
+        case 077:
+    switch(Instr & 0x3F) {
+        case 000:
+        switch(DIS_RC)
+        {
+            case 0: fcmp("fcmpu"); break;                                   // fcmpu
+            case 1: fcmp("fcmpo"); break;                                   // fcmpo
+            case 2: mcrfs(); break;                                         // mcrfs
+            default: ill(); break;
+        }
+        break;
+        case 014:
+        switch(DIS_RC)
+        {
+            case 1: mtfsb("mtfsb1"); break;                                 // mtfsb1
+            case 2: mtfsb("mtfsb0"); break;                                 // mtfsb0
+            case 4: mtfsfi(); break;                                        // mtfsfi
+            default: ill(); break;
+        }
+        break;
+        case 015:
+        switch(DIS_RC)
+        {
+            case 1: mtfsb("mtfsb1."); break;                                // mtfsb1.
+            case 2: mtfsb("mtfsb0."); break;                                // mtfsb0.
+            case 4: mtfsfi(); break;                                        // mtfsfi.
+            default: ill(); break;
+        }
+        break;
+        case 016:
+        switch(DIS_RC)
+        {
+            case 18: fpu("mffs", MASK_A|MASK_B, FPU_D); break;              // mffs
+            case 22: mtfsf(); break;                                        // mtfsf
+            default: ill(); break;
+        }
+        break;
+        case 017:
+        switch(DIS_RC)
+        {
+            case 18: fpu("mffs.", MASK_A|MASK_B, FPU_D); break;             // mffs.
+            case 22: mtfsf(); break;                                        // mtfsf.
+            default: ill(); break;
+        }
+        break;
+        case 020:
+        switch(DIS_RC)
+        {
+            case 1: fpu("fneg", MASK_A, FPU_DB); break;                     // fneg
+            case 2: fpu("fmr", MASK_A, FPU_DB); break;                      // fmr
+            case 4: fpu("fnabs", MASK_A, FPU_DB); break;                    // fnabs
+            case 8: fpu("fabs", MASK_A, FPU_DB); break;                     // fabs
+            default: ill(); break;
+        }
+        break;
+        case 021:
+        switch(DIS_RC)
+        {
+            case 1: fpu("fneg.", MASK_A, FPU_DB); break;                    // fneg
+            case 2: fpu("fmr.", MASK_A, FPU_DB); break;                     // fmr
+            case 4: fpu("fnabs.", MASK_A, FPU_DB); break;                   // fnabs
+            case 8: fpu("fabs.", MASK_A, FPU_DB); break;                    // fabs
+            default: ill(); break;
+        }
+        break;
+        case 030:
+        switch(DIS_RC)
+        {
+            case 0: fpu("frsp", MASK_A, FPU_DB); break;                     // frsp
+            default: ill(); break;
+        }
+        break;
+        case 031:
+        switch(DIS_RC)
+        {
+            case 0: fpu("frsp.", MASK_A, FPU_DB); break;                    // frsp.
+            default: ill(); break;
+        }
+        break;
+        case 034:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiw", MASK_A, FPU_DB); break;                    // fctiw
+#ifdef POWERPC_64
+            case 25: fpu("fctid", MASK_A, FPU_DB); break;                   // fctid
+            case 26: fpu("fcfid", MASK_A, FPU_DB); break;                   // fcfid
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 035:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiw.", MASK_A, FPU_DB); break;                   // fctiw.
+#ifdef POWERPC_64
+            case 25: fpu("fctid.", MASK_A, FPU_DB); break;                  // fctid.
+            case 26: fpu("fcfid.", MASK_A, FPU_DB); break;                  // fcfid.
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 036:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiwz", MASK_A, FPU_DB); break;                   // fctiwz
+#ifdef POWERPC_64
+            case 25: fpu("fctidz", MASK_A, FPU_DB); break;                  // fctidz
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 037:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiwz.", MASK_A, FPU_DB); break;                  // fctiwz.
+#ifdef POWERPC_64
+            case 25: fpu("fctidz.", MASK_A, FPU_DB); break;                 // fctidz.
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 044: fpu("fdiv", MASK_C, FPU_DAB); break;                      // fdivx
+        case 045: fpu("fdiv.", MASK_C, FPU_DAB); break;
+        case 050: fpu("fsub", MASK_C, FPU_DAB); break;                      // fsubx
+        case 051: fpu("fsub.", MASK_C, FPU_DAB); break;
+        case 052: fpu("fadd", MASK_C, FPU_DAB); break;                      // faddx
+        case 053: fpu("fadd.", MASK_C, FPU_DAB); break;
+#if !defined(GEKKO)
+        case 054: fpu("fsqrt", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtx
+        case 055: fpu("fsqrt.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+#endif
+        case 056: fpu("fsel", 0, FPU_DACB, PPC_DISA_OPTIONAL); break;       // fselx
+        case 057: fpu("fsel.", 0, FPU_DACB, PPC_DISA_OPTIONAL); break;
+        case 062: fpu("fmul", MASK_B, FPU_DAC); break;                      // fmulx
+        case 063: fpu("fmul.", MASK_B, FPU_DAC); break;
+        case 064: fpu("frsqrte", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // frsqrtex
+        case 065: fpu("frsqrte.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+        case 070: fpu("fmsub", 0, FPU_DACB); break;                         // fmsubx
+        case 071: fpu("fmsub.", 0, FPU_DACB); break;
+        case 072: fpu("fmadd", 0, FPU_DACB); break;                         // fmaddx
+        case 073: fpu("fmadd.", 0, FPU_DACB); break;
+        case 074: fpu("fnmsub", 0, FPU_DACB); break;                        // fnmsubx
+        case 075: fpu("fnmsub.", 0, FPU_DACB); break;
+        case 076: fpu("fnmadd", 0, FPU_DACB); break;                        // fnmaddx
+        case 077: fpu("fnmadd.", 0, FPU_DACB); break;
+        default: ill(); break;
+    } break;
+
+    /*
+     ***********************************************************************************
+     * GEKKO Extention.
+     ***********************************************************************************
+    */
+
+#ifdef  GEKKO
+        case 004:
+            if(((Instr >> 1) & 0x3FF) == 1014)
+            {
+                cache("dcbz_l", PPC_DISA_SPECIFIC);                         // dcbz_l
+            }
+            else switch((Instr >> 1) & 0x1f)
+            {
+            case 0: ps_cmpx((Instr >> 6) & 3); break;                       // ps_cmpXX
+            case 6: if(Instr & 0x40) ps_ldstx("lux");                       // ps_lux
+                    else ps_ldstx("lx"); break;                             // ps_lx
+            case 7: if(Instr & 0x40) ps_ldstx("stux");                      // ps_stux
+                    else ps_ldstx("stx"); break;                            // ps_stx
+            case 8:
+            switch((Instr >> 6) & 0x1f)
+            {
+                case 1: ps_db("neg", 1); break;                             // ps_negx
+                case 2: ps_db("mr", 1); break;                              // ps_mrx
+                case 4: ps_db("nabs", 1); break;                            // ps_nabsx
+                case 8: ps_db("abs", 1); break;                             // ps_absx
+                default: ill(); break;
+            } break;
+            case 10: ps_dacb("sum0"); break;                                // ps_sum0x
+            case 11: ps_dacb("sum1"); break;                                // ps_sum1x
+            case 12: ps_dac("muls0"); break;                                // ps_muls0x
+            case 13: ps_dac("muls1"); break;                                // ps_muls1x
+            case 14: ps_dacb("madds0"); break;                              // ps_madds0x
+            case 15: ps_dacb("madds1"); break;                              // ps_madds1x
+            case 16:
+            switch((Instr >> 6) & 0x1f)
+            {
+                case 16: ps_dab("merge00", 1); break;                       // ps_merge00x
+                case 17: ps_dab("merge01", 1); break;                       // ps_merge11x
+                case 18: ps_dab("merge10", 1); break;                       // ps_merge10x
+                case 19: ps_dab("merge11", 1); break;                       // ps_merge11x
+                default: ill(); break;
+            } break;
+            case 18: ps_dab("div"); break;                                  // ps_divx
+            case 20: ps_dab("sub"); break;                                  // ps_subx
+            case 21: ps_dab("add"); break;                                  // ps_addx
+            case 23: ps_dacb("sel"); break;                                 // ps_selx
+            case 24: ps_db("res"); break;                                   // ps_resx
+            case 25: ps_dac("mul"); break;                                  // ps_mulx
+            case 26: ps_db("rsqrte"); break;                                // ps_rsqrtex
+            case 28: ps_dacb("msub"); break;                                // ps_msubx
+            case 29: ps_dacb("madd"); break;                                // ps_maddx
+            case 30: ps_dacb("nmsub"); break;                               // ps_nmsubx
+            case 31: ps_dacb("nmadd"); break;                               // ps_nmaddx
+            default: ill(); break;
+        } break;
+        
+        case 070: ps_ldst("l"); break;                                      // psq_l
+        case 071: ps_ldst("lu"); break;                                     // psq_lu
+        case 074: ps_ldst("st"); break;                                     // psq_st
+        case 075: ps_ldst("stu"); break;                                    // psq_stu
+#endif  /* GEKKO */
+
+        default: ill(); break;
+    }
+
+#ifdef  UPPERCASE
+    strupr(o->mnemonic);
+#endif
+}
+
+char *PPCDisasmSimple(u64 pc, u32 instr)
+{
+    PPCD_CB dis_out;
+    static char output[256];
+
+    dis_out.pc = pc;
+    dis_out.instr = instr;
+
+    PPCDisasm(&dis_out);
+    sprintf(output, "%08X  %08X  %-10s %s", pc, instr, dis_out.mnemonic, dis_out.operands);
+    return output;
+}