/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   Mupen64plus - decoder.c                                               *
 *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
 *   Copyright (C) 2002 davFr                                              *
 *   Copyright (C) 2008 ZZT32                                              *
 *   Copyright (C) 2008 DarkJezter                                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "decoder.h"
#include "opprintf.h"

static int  mot;
static char *op;
static char *args;
static int pc;

static void RESERV(){
    sprintf(op, "INVLD(%02X)       0x%08X", (mot>>26)&0x3F, mot);
}

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ SPECIAL ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void SLL()
{
    if( !mot )
        mr4kd_sprintf( op, "NOP", mot, pc, "%n0" );
    
    else{
        mr4kd_sprintf( op, "SLL", mot, pc, "%ns%rd, %rt, %sa" );
    }
}

static void SRL(){
    mr4kd_sprintf( op, "SRL", mot, pc, "%ns%rd, %rt, %sa" );
}

static void SRA(){
    mr4kd_sprintf( op, "SRA", mot, pc, "%ns%rd, %rt, %sa" );
}

static void SLLV(){
    mr4kd_sprintf( op, "SLLV", mot, pc, "%ns%rd, %rt, %rs" );
}

static void SRLV(){
    mr4kd_sprintf( op, "SRLV", mot, pc, "%ns%rd, %rt, %rs" );
}

static void SRAV(){
    mr4kd_sprintf( op, "SRAV", mot, pc, "%ns%rd, %rt, %rs" );

}

static void JR(){
    mr4kd_sprintf( op, "JR", mot, pc, "%ns%rs" );
}

static void JALR(){
    mr4kd_sprintf( op, "JALR", mot, pc, "%ns%rd, %rs" );
}

static void SYSCALL(){
    mr4kd_sprintf( op, "SYSCALL", mot, pc, "%n0" );
}

static void BREAK(){
    mr4kd_sprintf( op, "BREAK", mot, pc, "%n0" );
}

static void SYNC(){
    mr4kd_sprintf( op, "SYNC", mot, pc, "%n0" );
}

static void MFHI(){
    mr4kd_sprintf( op, "MFHI", mot, pc, "%ns%rd" );
}

static void MTHI(){
    mr4kd_sprintf( op, "MTHI", mot, pc, "%ns%rs" );
}

static void MFLO(){
    mr4kd_sprintf( op, "MFLO", mot, pc, "%ns%rd" );
}

static void MTLO(){
    mr4kd_sprintf( op, "MTLO", mot, pc, "%ns%rs" );
}

static void DSLLV(){
    mr4kd_sprintf( op, "DSLLV", mot, pc, "%ns%rd, %rt, %rs" );
}

static void DSRLV(){
    mr4kd_sprintf( op, "DSRLV", mot, pc, "%ns%rd, %rt, %rs" );
}

static void DSRAV(){
    mr4kd_sprintf( op, "DSRAV", mot, pc, "%ns%rd, %rt, %rs" );
}

static void MULT(){
    mr4kd_sprintf( op, "MULT", mot, pc, "%ns%rs, %rt" );
}

static void MULTU(){
    mr4kd_sprintf( op, "MULTU", mot, pc, "%ns%rs, %rt" );
}

static void DIV(){
    mr4kd_sprintf( op, "DIV", mot, pc, "%ns%rs, %rt" );
}

static void DIVU(){
    mr4kd_sprintf( op, "DIVU", mot, pc, "%ns%rs, %rt" ); 
}

static void DMULT(){
    mr4kd_sprintf( op, "DMULT", mot, pc, "%ns%rs, %rt" ); 
}

static void DMULTU(){
    mr4kd_sprintf( op, "DMULTU", mot, pc, "%ns%rs, %rt" ); 
}

static void DDIV(){
    mr4kd_sprintf( op, "DDIV", mot, pc, "%ns%rs, %rt" ); 
}

static void DDIVU(){
    mr4kd_sprintf( op, "DDIVU", mot, pc, "%ns%rs, %rt" ); 
}

static void ADD(){
    mr4kd_sprintf( op, "ADD", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void ADDU(){
    mr4kd_sprintf( op, "ADDU", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void SUB()
{
    mr4kd_sprintf( op, "SUB", mot, pc, "%ns%rd, %rs, %rt" );
}

static void SUBU(){
    mr4kd_sprintf( op, "SUBU", mot, pc, "%ns%rd, %rs, %rt" );
}

static void AND(){
    mr4kd_sprintf( op, "AND", mot, pc, "%ns%rd, %rs, %rt" );
}

static void OR(){
    mr4kd_sprintf( op, "OR", mot, pc, "%ns%rd, %rs, %rt" );
}

static void XOR(){
    mr4kd_sprintf( op, "XOR", mot, pc, "%ns%rd, %rs, %rt" );
}

static void NOR(){
    mr4kd_sprintf( op, "NOR", mot, pc, "%ns%rd, %rs, %rt" );
}

static void SLT(){
    mr4kd_sprintf( op, "SLT", mot, pc, "%ns%rd, %rs, %rt" );
}

static void SLTU(){
    mr4kd_sprintf( op, "SLTU", mot, pc, "%ns%rd, %rs, %rt" );
}

static void DADD(){
    mr4kd_sprintf( op, "DADD", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void DADDU(){
    mr4kd_sprintf( op, "DADDU", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void DSUB(){
    mr4kd_sprintf( op, "DSUB", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void DSUBU(){
    mr4kd_sprintf( op, "DSUBU", mot, pc, "%ns%rd, %rs, %rt" ); 
}

static void TGE(){
    mr4kd_sprintf( op, "TGE", mot, pc, "%ns%rs, %rt" ); 
}

static void TGEU(){
    mr4kd_sprintf( op, "TGEU", mot, pc, "%ns%rs, %rt" ); 
}

static void TLT(){
    mr4kd_sprintf( op, "TLT", mot, pc, "%ns%rs, %rt" ); 
}

static void TLTU(){
    mr4kd_sprintf( op, "TLTU", mot, pc, "%ns%rs, %rt" ); 
}

static void TEQ(){
    mr4kd_sprintf( op, "TEQ", mot, pc, "%ns%rs, %rt" ); 
}

static void TNE(){
    mr4kd_sprintf( op, "TNE", mot, pc, "%ns%rs, %rt" ); 
}

static void DSLL(){
    mr4kd_sprintf( op, "DSLL", mot, pc, "%ns%rd, %rt, %sa" ); 
}

static void DSRL(){
    mr4kd_sprintf( op, "DSRL", mot, pc, "%ns%rd, %rt, %sa" ); 
}

static void DSRA(){
    mr4kd_sprintf( op, "DSRA", mot, pc, "%ns%rd, %rt, %sa" ); 
}

static void DSLL32(){
    mr4kd_sprintf( op, "DSLL32", mot, pc, "%ns%rd, %rt, %sa" );
}

static void DSRL32(){
    mr4kd_sprintf( op, "DSRL32", mot, pc, "%ns%rd, %rt, %sa" );
}

static void DSRA32(){
    mr4kd_sprintf( op, "DSRA32", mot, pc, "%ns%rd, %rt, %sa" );
}

static void special()
{
//  sprintf(op, "[00] SPECIAL");
    
    switch( mot & 0x3F)
    {
        case 0x00: SLL();   break;
        case 0x02: SRL();   break;
        case 0x03: SRA();   break;
        case 0x04: SLLV();  break;
        case 0x06: SRLV();  break;
        case 0x07: SRAV();  break;
        case 0x08: JR();    break;
        case 0x09: JALR();  break;
        case 0x0C: SYSCALL();   break;
        case 0x0D: BREAK(); break;
        case 0x0F: SYNC();  break;
        case 0x10: MFHI();  break;
        case 0x11: MTHI();  break;
        case 0x12: MFLO();  break;
        case 0x13: MTLO();  break;
        case 0x14: DSLLV(); break;
        case 0x16: DSRLV(); break;
        case 0x17: DSRAV(); break;
        case 0x18: MULT();  break;
        case 0x19: MULTU(); break;
        case 0x1A: DIV();   break;
        case 0x1B: DIVU();  break;
        case 0x1C: DMULT(); break;
        case 0x1D: DMULTU();    break;
        case 0x1E: DDIV();  break;
        case 0x1F: DDIVU(); break;
        case 0x20: ADD();   break;
        case 0x21: ADDU();  break;
        case 0x22: SUB();   break;
        case 0x23: SUBU();  break;
        case 0x24: AND();   break;
        case 0x25: OR();    break;
        case 0x26: XOR();   break;
        case 0x27: NOR();   break;
        case 0x2A: SLT();   break;
        case 0x2B: SLTU();  break;
        case 0x2C: DADD();  break;
        case 0x2D: DADDU(); break;
        case 0x2E: DSUB();  break;
        case 0x2F: DSUBU(); break;
        case 0x30: TGE();   break;
        case 0x31: TGEU();  break;
        case 0x32: TLT();   break;
        case 0x33: TLTU();  break;
        case 0x34: TEQ();   break;
        case 0x36: TNE();   break;
        case 0x38: DSLL();  break;
        case 0x3A: DSRL();  break;
        case 0x3B: DSRA();  break;
        case 0x3C: DSLL32();    break;
        case 0x3E: DSRL32();    break;
        case 0x3F: DSRA32();    break;
        default :  RESERV(); //just to be sure
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ REGIMM ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void BLTZ(){
    mr4kd_sprintf( op, "BLTZ", mot, pc, "%ns%rs, %br" );
}

static void BGEZ(){
    mr4kd_sprintf( op, "BGEZ", mot, pc, "%ns%rs, %br" );
}

static void BLTZL(){
    mr4kd_sprintf( op, "BLTZL", mot, pc, "%ns%rs, %br" );
}

static void BGEZL(){
    mr4kd_sprintf( op, "BGEZL", mot, pc, "%ns%rs, %br" );
}

static void TGEI(){
    mr4kd_sprintf( op, "TGEI", mot, pc, "%ns%rs, %ih" );
}

static void TGEIU(){
    mr4kd_sprintf( op, "TGEIU", mot, pc, "%ns%rs, %ih" );
}

static void TLTI(){
    mr4kd_sprintf( op, "TLTI", mot, pc, "%ns%rs, %ih" );
}

static void TLTIU(){
    mr4kd_sprintf( op, "TLTIU", mot, pc, "%ns%rs, %ih" );
}

static void TEQI(){
    mr4kd_sprintf( op, "TEQI", mot, pc, "%ns%rs, %ih" );
}

static void TNEI(){
    mr4kd_sprintf( op, "TNEI", mot, pc, "%ns%rs, %ih" );
}

static void BLTZAL(){
    mr4kd_sprintf( op, "BLTZAL", mot, pc, "%ns%rs, %br" );
}

static void BGEZAL(){
    mr4kd_sprintf( op, "BGEZAL", mot, pc, "%ns%rs, %br" );
}

static void BLTZALL(){
    mr4kd_sprintf( op, "BLTZALL", mot, pc, "%ns%rs, %br" );
}

static void BGEZALL(){
    mr4kd_sprintf( op, "BGEZALL", mot, pc, "%ns%rs, %br" );
}

static void regimm()
{
//  sprintf(op, "[01] REGIMM");
    
    switch( (mot>>16) & 0x1F)
    {
        case 0x00: BLTZ();  break;
        case 0x01: BGEZ();  break;
        case 0x02: BLTZL(); break;
        case 0x03: BGEZL(); break;
        case 0x08: TGEI();  break;
        case 0x09: TGEIU(); break;
        case 0x0A: TLTI();  break;
        case 0x0B: TLTIU(); break;
        case 0x0C: TEQI();  break;
        case 0x0E: TNEI();  break;
        case 0x10: BLTZAL();    break;
        case 0x11: BGEZAL();    break;
        case 0x12: BLTZALL();   break;
        case 0x13: BGEZALL();   break;
        default: RESERV();
        }
}


//]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ ... ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[

static void J(){
    mr4kd_sprintf( op, "J", mot, pc, "%ns%jm" );
}

static void JAL(){
    mr4kd_sprintf( op, "JAL", mot, pc, "%ns%jm" );
}

static void BEQ(){
    mr4kd_sprintf( op, "BEQ", mot, pc, "%ns%rs, %rt, %br" );
}

static void BNE(){
    mr4kd_sprintf( op, "BNE", mot, pc, "%ns%rs, %rt, %br" );
}

static void BLEZ(){
    mr4kd_sprintf( op, "BLEZ", mot, pc, "%ns%rs, %br" );
}

static void BGTZ(){
    mr4kd_sprintf( op, "BGTZ", mot, pc, "%ns%rs, %br" );
}

static void ADDI(){
    mr4kd_sprintf( op, "ADDI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void ADDIU(){
    mr4kd_sprintf( op, "ADDIU", mot, pc, "%ns%rt, %rs, %ih" );
}

static void SLTI(){
    mr4kd_sprintf( op, "SLTI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void SLTIU(){
    mr4kd_sprintf( op, "SLTIU", mot, pc, "%ns%rt, %rs, %ih" );
}

static void ANDI(){
    mr4kd_sprintf( op, "ANDI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void ORI(){
    mr4kd_sprintf( op, "ORI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void XORI(){
    mr4kd_sprintf( op, "XORI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void LUI(){
    mr4kd_sprintf( op, "LUI", mot, pc, "%ns%rt, %ih" );
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ cop0 ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void MFC0(){
    mr4kd_sprintf( op, "MFC0", mot, pc, "%ns%rt, %cp" );
}   

static void MTC0(){
    mr4kd_sprintf( op, "MTC0", mot, pc, "%ns%rt, %cp" );
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ tlb ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void TLBR(){   
    mr4kd_sprintf( op, "TLBR", mot, pc, "%n0" );
}   
    
static void TLBWI(){
    mr4kd_sprintf( op, "TLBWI", mot, pc, "%n0" );
}   

static void TLBWR(){
    mr4kd_sprintf( op, "TLBWR", mot, pc, "%n0" );
}   

static void TLBP(){
    mr4kd_sprintf( op, "TLBP", mot, pc, "%n0" );
}   

static void ERET(){
    mr4kd_sprintf( op, "ERET", mot, pc, "%n0" );
}   

static void tlb()
{
//  sprintf(op, "[10] tlb");
    
    switch( mot & 0x3F)
    {
        case 0x01: TLBR()   ; break;
        case 0x02: TLBWI()  ; break;
        case 0x06: TLBWR()  ; break;
        case 0x08: TLBP()   ; break;
        case 0x18: ERET()   ; break;
        default: RESERV();
    }
}

static void cop0()
{
//  sprintf(op, "[10] COP0");
    
    switch( (mot>>21) & 0x1F)
    {
        case 0x00: MFC0()   ; break;
        case 0x04: MTC0()   ; break;
        case 0x10: tlb()    ; break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ cop1 ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void MFC1(){
    mr4kd_sprintf( op, "MFC1", mot, pc, "%ns%rt, %fs" );
}

static void DMFC1(){
    mr4kd_sprintf( op, "DMFC1", mot, pc, "%ns%rt, %fs" );
}

static void CFC1(){
    mr4kd_sprintf( op, "CFC1", mot, pc, "%ns%rt, %rd" );
}

static void MTC1(){
    mr4kd_sprintf( op, "MTC1", mot, pc, "%ns%ft, %rd" );
}

static void DMTC1(){
    mr4kd_sprintf( op, "DMTC1", mot, pc, "%ns%ft, %rd" );
}

static void CTC1(){
    mr4kd_sprintf( op, "CTC1", mot, pc, "%ns%rt, %rd" );
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ BC ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void BC1F(){
    mr4kd_sprintf( op, "BC1F", mot, pc, "%ns%br" );
}

static void BC1T(){
    mr4kd_sprintf( op, "BC1T", mot, pc, "%ns%br" );
    
}

static void BC1FL(){
    mr4kd_sprintf( op, "BC1FL", mot, pc, "%ns%br" );
    
}

static void BC1TL(){
    mr4kd_sprintf( op, "BC1TL", mot, pc, "%ns%br" );
}

static void BC()
{
//  sprintf(op, "[11] BC");

    switch( (mot>>16) & 3)
    {
        case 0x00: BC1F();  break;
        case 0x01: BC1T();  break;
        case 0x02: BC1FL(); break;
        case 0x03: BC1TL(); break;
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ S ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void ADD_S(){
    mr4kd_sprintf( op, "ADD.S", mot, pc, "%ns%fd, %fs, %ft" );
}

static void SUB_S(){
    mr4kd_sprintf( op, "SUB.S", mot, pc, "%ns%fd, %fs, %ft" );
}

static void MUL_S(){
    mr4kd_sprintf( op, "MUL.S", mot, pc, "%ns%fd, %fs, %ft" );
}

static void DIV_S(){
    mr4kd_sprintf( op, "DIV.S", mot, pc, "%ns%fd, %fs, %ft" );
}

static void SQRT_S(){
    mr4kd_sprintf( op, "SQRT.S", mot, pc, "%ns%fd, %fs" );
}

static void ABS_S(){
    mr4kd_sprintf( op, "ABS.S", mot, pc, "%ns%fd, %fs" );
}

static void MOV_S(){
    mr4kd_sprintf( op, "MOV.S", mot, pc, "%ns%fd, %fs" );
}

static void NEG_S(){
    mr4kd_sprintf( op, "NEG.S", mot, pc, "%ns%fd, %fs" );
}

static void ROUND_L_S(){
    mr4kd_sprintf( op, "ROUND.L.S", mot, pc, "%ns%fd, %fs" );
}

static void TRUNC_L_S(){
    mr4kd_sprintf( op, "TRUNC.L.S", mot, pc, "%ns%fd, %fs" );
}

static void CEIL_L_S(){
    mr4kd_sprintf( op, "CEIL.L.S", mot, pc, "%ns%fd, %fs" );
}

static void FLOOR_L_S(){
    mr4kd_sprintf( op, "FLOOR.L.S", mot, pc, "%ns%fd, %fs" );
}

static void ROUND_W_S(){
    mr4kd_sprintf( op, "ROUND.W.S", mot, pc, "%ns%fd, %fs" );
}

static void TRUNC_W_S(){
    mr4kd_sprintf( op, "TRUNC.W.S", mot, pc, "%ns%fd, %fs" );
}

static void CEIL_W_S(){
    mr4kd_sprintf( op, "CEIL.W.S", mot, pc, "%ns%fd, %fs" );
}

static void FLOOR_W_S(){
    mr4kd_sprintf( op, "FLOOR.W.S", mot, pc, "%ns%fd, %fs" );
}

static void CVT_D_S(){
    mr4kd_sprintf( op, "CVT.D.S", mot, pc, "%ns%fd, %fs" );
}

static void CVT_W_S(){
    mr4kd_sprintf( op, "CVT.W.S", mot, pc, "%ns%fd, %fs" );
}

static void CVT_L_S(){
    mr4kd_sprintf( op, "CVT.L.S", mot, pc, "%ns%fd, %fs" );
}


static void C_F_S(){
    mr4kd_sprintf( op, "C.F.S", mot, pc, "%ns%fs, %ft" );
}

static void C_UN_S(){
    mr4kd_sprintf( op, "C.UN.S", mot, pc, "%ns%fs, %ft" );
}

static void C_EQ_S(){
    mr4kd_sprintf( op, "C.EQ.S", mot, pc, "%ns%fs, %ft" );
}

static void C_UEQ_S(){
    mr4kd_sprintf( op, "C.UEQ.S", mot, pc, "%ns%fs, %ft" );
}

static void C_OLT_S(){
    mr4kd_sprintf( op, "C.OLT.S", mot, pc, "%ns%fs, %ft" );
}

static void C_ULT_S(){
    mr4kd_sprintf( op, "C.ULT.S", mot, pc, "%ns%fs, %ft" );
}

static void C_OLE_S(){
    mr4kd_sprintf( op, "C.OLE.S", mot, pc, "%ns%fs, %ft" );
}

static void C_ULE_S(){
    mr4kd_sprintf( op, "C.ULE.S", mot, pc, "%ns%fs, %ft" );
}

static void C_SF_S(){
    mr4kd_sprintf( op, "C.SF.S", mot, pc, "%ns%fs, %ft" );
}

static void C_NGLE_S(){
    mr4kd_sprintf( op, "C.NGLE.S", mot, pc, "%ns%fs, %ft" );
}

static void C_SEQ_S(){
    mr4kd_sprintf( op, "C.SEQ.S", mot, pc, "%ns%fs, %ft" );
}

static void C_NGL_S(){
    mr4kd_sprintf( op, "C.NGL.S", mot, pc, "%ns%fs, %ft" );
}

static void C_LT_S(){
    mr4kd_sprintf( op, "C.LT.S", mot, pc, "%ns%fs, %ft" );
}

static void C_NGE_S(){
    mr4kd_sprintf( op, "C.NGE.S", mot, pc, "%ns%fs, %ft" );
}

static void C_LE_S(){
    mr4kd_sprintf( op, "C.LE.S", mot, pc, "%ns%fs, %ft" );
}

static void C_NGT_S(){
    mr4kd_sprintf( op, "C.NGT.S", mot, pc, "%ns%fs, %ft" );
}


static void S()
{
//  sprintf(op, "[11] S");
    
    switch( mot & 0x3F)
    {
        case 0x00: ADD_S(); break;
        case 0x01: SUB_S(); break;
        case 0x02: MUL_S(); break;
        case 0x03: DIV_S(); break;
        case 0x04: SQRT_S();    break;
        case 0x05: ABS_S(); break;
        case 0x06: MOV_S(); break;
        case 0x07: NEG_S(); break;
        case 0x08: ROUND_L_S(); break;
        case 0x09: TRUNC_L_S(); break;
        case 0x0A: CEIL_L_S();  break;
        case 0x0B: FLOOR_L_S(); break;
        case 0x0C: ROUND_W_S(); break;
        case 0x0D: TRUNC_W_S(); break;
        case 0x0E: CEIL_W_S();  break;
        case 0x0F: FLOOR_W_S(); break;
        case 0x21: CVT_D_S();   break;
        case 0x24: CVT_W_S();   break;
        case 0x25: CVT_L_S();   break;
        case 0x30: C_F_S(); break;
        case 0x31: C_UN_S();    break;
        case 0x32: C_EQ_S();    break;
        case 0x33: C_UEQ_S();   break;
        case 0x34: C_OLT_S();   break;
        case 0x35: C_ULT_S();   break;
        case 0x36: C_OLE_S();   break;
        case 0x37: C_ULE_S();   break;
        case 0x38: C_SF_S();    break;
        case 0x39: C_NGLE_S();  break;
        case 0x3A: C_SEQ_S();   break;
        case 0x3B: C_NGL_S();   break;
        case 0x3C: C_LT_S();    break;
        case 0x3D: C_NGE_S();   break;
        case 0x3E: C_LE_S();    break;
        case 0x3F: C_NGT_S();   break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ D ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//


static void ADD_D(){
    mr4kd_sprintf( op, "ADD.D", mot, pc, "%ns%fd, %fs, %ft" );
}

static void SUB_D(){
    mr4kd_sprintf( op, "SUB.D", mot, pc, "%ns%fd, %fs, %ft" );
}

static void MUL_D(){
    mr4kd_sprintf( op, "MUL.D", mot, pc, "%ns%fd, %fs, %ft" );
}

static void DIV_D(){
    mr4kd_sprintf( op, "DIV.D", mot, pc, "%ns%fd, %fs, %ft" );
}

static void SQRT_D(){
    mr4kd_sprintf( op, "SQRT.D", mot, pc, "%ns%fd, %fs" );
}

static void ABS_D(){
    mr4kd_sprintf( op, "ABS.D", mot, pc, "%ns%fd, %fs" );
}

static void MOV_D(){
    mr4kd_sprintf( op, "MOV.D", mot, pc, "%ns%fd, %fs" );
}

static void NEG_D(){
    mr4kd_sprintf( op, "NEG.D", mot, pc, "%ns%fd, %fs" );
}

static void ROUND_L_D(){
    mr4kd_sprintf( op, "ROUND.L.D", mot, pc, "%ns%fd, %fs" );
}

static void TRUNC_L_D(){
    mr4kd_sprintf( op, "TRUNC.L.D", mot, pc, "%ns%fd, %fs" );
}

static void CEIL_L_D(){
    mr4kd_sprintf( op, "CEIL.L.D", mot, pc, "%ns%fd, %fs" );
}

static void FLOOR_L_D(){
    mr4kd_sprintf( op, "FLOOR.L.D", mot, pc, "%ns%fd, %fs" );
}

static void ROUND_W_D(){
    mr4kd_sprintf( op, "ROUND.W.D", mot, pc, "%ns%fd, %fs" );
}

static void TRUNC_W_D(){
    mr4kd_sprintf( op, "TRUNC.W.D", mot, pc, "%ns%fd, %fs" );
}

static void CEIL_W_D(){
    mr4kd_sprintf( op, "CEIL.W.D", mot, pc, "%ns%fd, %fs" );
}

static void FLOOR_W_D(){
    mr4kd_sprintf( op, "FLOOR.W.D", mot, pc, "%ns%fd, %fs" );
}

static void CVT_S_D(){
    mr4kd_sprintf( op, "CVT.S.D", mot, pc, "%ns%fd, %fs" );
}

static void CVT_W_D(){
    mr4kd_sprintf( op, "CVT.W.D", mot, pc, "%ns%fd, %fs" );
}

static void CVT_L_D(){
    mr4kd_sprintf( op, "CVT.L.D", mot, pc, "%ns%fd, %fs" );
}



static void C_F_D(){
    mr4kd_sprintf( op, "C.F.D", mot, pc, "%ns%fs, %ft" );
}

static void C_UN_D(){
    mr4kd_sprintf( op, "C.UN.D", mot, pc, "%ns%fs, %ft" );
}

static void C_EQ_D(){
    mr4kd_sprintf( op, "C.EQ.D", mot, pc, "%ns%fs, %ft" );
}

static void C_UEQ_D(){
    mr4kd_sprintf( op, "C.UEQ.D", mot, pc, "%ns%fs, %ft" );
}

static void C_OLT_D(){
    mr4kd_sprintf( op, "C.OLT.D", mot, pc, "%ns%fs, %ft" );
}

static void C_ULT_D(){
    mr4kd_sprintf( op, "C.ULT.D", mot, pc, "%ns%fs, %ft" );
}

static void C_OLE_D(){
    mr4kd_sprintf( op, "C.OLE.D", mot, pc, "%ns%fs, %ft" );
}

static void C_ULE_D(){
    mr4kd_sprintf( op, "C.ULE.D", mot, pc, "%ns%fs, %ft" );
}

static void C_SF_D(){
    mr4kd_sprintf( op, "C.SF.D", mot, pc, "%ns%fs, %ft" );
}

static void C_NGLE_D(){
    mr4kd_sprintf( op, "C.NGLE.D", mot, pc, "%ns%fs, %ft" );
}

static void C_SEQ_D(){
    mr4kd_sprintf( op, "C.SEQ.D", mot, pc, "%ns%fs, %ft" );
}

static void C_NGL_D(){
    mr4kd_sprintf( op, "C.NGL.D", mot, pc, "%ns%fs, %ft" );
}

static void C_LT_D(){
    mr4kd_sprintf( op, "C.LT.D", mot, pc, "%ns%fs, %ft" );
}

static void C_NGE_D(){
    mr4kd_sprintf( op, "C.NGE.D", mot, pc, "%ns%fs, %ft" );
}

static void C_LE_D(){
    mr4kd_sprintf( op, "C.LE.D", mot, pc, "%ns%fs, %ft" );
}

static void C_NGT_D(){
    mr4kd_sprintf( op, "C.NGT.D", mot, pc, "%ns%fs, %ft" );
}


static void D()
{
//  sprintf(op, "[11] D");

    switch( mot & 0x3F)
    {
        case 0x00: ADD_D(); break;
        case 0x01: SUB_D(); break;
        case 0x02: MUL_D(); break;
        case 0x03: DIV_D(); break;
        case 0x04: SQRT_D();    break;
        case 0x05: ABS_D(); break;
        case 0x06: MOV_D(); break;
        case 0x07: NEG_D(); break;
        case 0x08: ROUND_L_D(); break;
        case 0x09: TRUNC_L_D(); break;
        case 0x0A: CEIL_L_D();  break;
        case 0x0B: FLOOR_L_D(); break;
        case 0x0C: ROUND_W_D(); break;
        case 0x0D: TRUNC_W_D(); break;
        case 0x0E: CEIL_W_D();  break;
        case 0x0F: FLOOR_W_D(); break;
        case 0x20: CVT_S_D();   break;
        case 0x24: CVT_W_D();   break;
        case 0x25: CVT_L_D();   break;
        case 0x30: C_F_D(); break;
        case 0x31: C_UN_D();    break;
        case 0x32: C_EQ_D();    break;
        case 0x33: C_UEQ_D();   break;
        case 0x34: C_OLT_D();   break;
        case 0x35: C_ULT_D();   break;
        case 0x36: C_OLE_D();   break;
        case 0x37: C_ULE_D();   break;
        case 0x38: C_SF_D();    break;
        case 0x39: C_NGLE_D();  break;
        case 0x3A: C_SEQ_D();   break;
        case 0x3B: C_NGL_D();   break;
        case 0x3C: C_LT_D();    break;
        case 0x3D: C_NGE_D();   break;
        case 0x3E: C_LE_D();    break;
        case 0x3F: C_NGT_D();   break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ W ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void CVT_S_W(){
    mr4kd_sprintf( op, "CVT.S.W", mot, pc, "%ns%fd, %fs" );
}

static void CVT_D_W(){
    mr4kd_sprintf( op, "CVT.D.W", mot, pc, "%ns%fd, %fs" );
}


static void W()
{
//  sprintf(op, "[11] W");
//  sprintf(args, " ");
    
    switch( mot & 0x3F)
    {
        case 0x20: CVT_S_W();   break;
        case 0x21: CVT_D_W();   break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ L ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void CVT_S_L(){
    mr4kd_sprintf( op, "CVT.S.L", mot, pc, "%ns%fd, %fs" );
}

static void CVT_D_L(){
    mr4kd_sprintf( op, "CVT.D.L", mot, pc, "%ns%fd, %fs" );
}


static void L(){
//  sprintf(op, "[11] L");
//  sprintf(args, " ");

    switch( mot & 0x3F)
    {
        case 0x20: CVT_S_L();   break;
        case 0x21: CVT_D_L();   break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ cop1 ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void cop1()
{
//  sprintf(op, "[11] COP1");
    
    switch( (mot>>21) & 0x1F)
    {
        case 0x00: MFC1();  break;
        case 0x01: DMFC1(); break;
        case 0x02: CFC1();  break;
        case 0x04: MTC1();  break;
        case 0x05: DMTC1(); break;
        case 0x06: CTC1();  break;
        case 0x08: BC();    break;
        case 0x10: S();     break;
        case 0x11: D();     break;
        case 0x14: W();     break;
        case 0x15: L();     break;
        default: RESERV();
    }
}


//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ ... ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//

static void BEQL(){
    mr4kd_sprintf( op, "BEQL", mot, pc, "%ns%rs, %rt, %br" );
}

static void BNEL(){
    mr4kd_sprintf( op, "BNEL", mot, pc, "%ns%rs, %rt, %br" );
}

static void BLEZL(){
    mr4kd_sprintf( op, "BLEZL", mot, pc, "%ns%rs, %rt, %br" );
}

static void BGTZL(){
    mr4kd_sprintf( op, "BGTZL", mot, pc, "%ns%rs, %rt, %br" );
}


static void DADDI(){
    mr4kd_sprintf( op, "DADDI", mot, pc, "%ns%rt, %rs, %ih" );
}

static void DADDIU(){
    mr4kd_sprintf( op, "DADDIU", mot, pc, "%ns%rt, %rs, %ih" );
}


static void LDL(){
    mr4kd_sprintf( op, "LDL", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LDR(){
    mr4kd_sprintf( op, "LDR", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LB(){
    mr4kd_sprintf( op, "LB", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LH(){
    mr4kd_sprintf( op, "LH", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LWL(){
    mr4kd_sprintf( op, "LWL", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LW(){
    mr4kd_sprintf( op, "LW", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LBU(){
    mr4kd_sprintf( op, "LBU", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LHU(){
    mr4kd_sprintf( op, "LHU", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LWR(){
    mr4kd_sprintf( op, "LWR", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LWU(){
    mr4kd_sprintf( op, "LWU", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SB(){
    mr4kd_sprintf( op, "SB", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SH(){
    mr4kd_sprintf( op, "SH", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SWL(){
    mr4kd_sprintf( op, "SWL", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SW(){
    mr4kd_sprintf( op, "SW", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SDL(){
    mr4kd_sprintf( op, "SDL", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SDR(){
    mr4kd_sprintf( op, "SDR", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SWR(){
    mr4kd_sprintf( op, "SWR", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void CACHE(){
    mr4kd_sprintf( op, "CACHE", mot, pc, "%ns%rt, %ih(%rs)");
}

static void LL(){
    mr4kd_sprintf( op, "LL", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LWC1(){
    mr4kd_sprintf( op, "LWC1", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LLD(){
    mr4kd_sprintf( op, "LLD", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LDC1(){
    mr4kd_sprintf( op, "LDC1", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void LD(){
    mr4kd_sprintf( op, "LD", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SC(){
    mr4kd_sprintf( op, "SC", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SWC1(){
    mr4kd_sprintf( op, "SWC1", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SCD(){
    mr4kd_sprintf( op, "SCD", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SDC1(){
    mr4kd_sprintf( op, "SDC1", mot, pc, "%ns%rt, %ih(%rs)" );
}

static void SD(){
    mr4kd_sprintf( op, "SD", mot, pc, "%ns%rt, %ih(%rs)" );
}



//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ DECODE_OP ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//
void r4300_decode_op( uint32 instr, char *opcode, char *arguments, int counter )
{
    char buffer[256]; int result;
    mr4kd_disassemble( instr, counter, buffer );
    
    /* Split it up */
    if( (result = sscanf( buffer, "%s %s", opcode, arguments )) == 1 )
        strcpy( arguments, " " );
    else
        strcpy( arguments, buffer + 16);
}

/* Disassemble */
void mr4kd_disassemble ( uint32 instruction, uint32 counter, char * buffer )
{
    mot = instruction;
    pc  = counter;
    op  = buffer;
    
    switch((mot>>26)&0x3F)
    {
        case 0x00: special();   break;
        case 0x01: regimm();    break;
        case 0x02: J();     break;
        case 0x03: JAL();   break;
        case 0x04: BEQ();   break;
        case 0x05: BNE();   break;
        case 0x06: BLEZ();  break;
        case 0x07: BGTZ();  break;
        case 0x08: ADDI();  break;
        case 0x09: ADDIU(); break;
        case 0x0A: SLTI();  break;
        case 0x0B: SLTIU(); break;
        case 0x0C: ANDI();  break;
        case 0x0D: ORI();   break;
        case 0x0E: XORI();  break;
        case 0x0F: LUI();   break;
        case 0x10: cop0();  break;
        case 0x11: cop1();  break;
        case 0x14: BEQL();  break;
        case 0x15: BNEL();  break;
        case 0x16: BLEZL(); break;
        case 0x17: BGTZL(); break;
        case 0x18: DADDI(); break;
        case 0x19: DADDIU();    break;
        case 0x1A: LDL();   break;
        case 0x1B: LDR();   break;
        case 0x20: LB();    break;
        case 0x21: LH();    break;
        case 0x22: LWL();   break;
        case 0x23: LW();    break;
        case 0x24: LBU();   break;
        case 0x25: LHU();   break;
        case 0x26: LWR();   break;
        case 0x27: LWU();   break;
        case 0x28: SB();    break;
        case 0x29: SH();    break;
        case 0x2A: SWL();   break;
        case 0x2B: SW();    break;
        case 0x2C: SDL();   break;
        case 0x2D: SDR();   break;
        case 0x2E: SWR();   break;
        case 0x2F: CACHE(); break;
        case 0x30: LL();    break;
        case 0x31: LWC1();  break;
        case 0x34: LLD();   break;
        case 0x35: LDC1();  break;
        case 0x37: LD();    break;
        case 0x38: SC();    break;
        case 0x39: SWC1();  break;
        case 0x3C: SCD();   break;
        case 0x3D: SDC1();  break;
        case 0x3F: SD();    break;
        default: RESERV();
    }
}

