#ifndef RSPDIS_H
#define RSPDIS_H

#define DECODE_JUMP         (((raw_opcode_ulong & 0x03FFFFFF) << 2) | (raw_opcode_addr & 0xF0000000))
#define DECODE_IMMED        ((uint)((raw_opcode[2] << 8) | raw_opcode[3]))

#define DECODE_RS           ((raw_opcode[0] & 0x03) << 3 | (raw_opcode[1] >> 5))
#define DECODE_RT           (raw_opcode[1] & 0x1F)
#define DECODE_RD           (raw_opcode[2] >> 3)
#define DECODE_SA           ((raw_opcode[2] & 0x07) << 2 | (raw_opcode[3] >> 6))
#define DECODE_FS           (DECODE_RD)
#define DECODE_FT           (DECODE_RT)
#define DECODE_FD           (DECODE_SA)

#define DECODE_BASE         (DECODE_RS)
#define DECODE_OFFSET       ((ulong)(((ulong)(SignExtend16(DECODE_IMMED)) << 2) + raw_opcode_addr + 4))

#define DECODE_SYSCALL      ((raw_opcode_ulong & 0x03FFFFFF) >> 6)
#define DECODE_BREAK        (DECODE_SYSCALL)

#define DECODE_OPCODE       (raw_opcode[0] >> 2)
#define DECODE_FUNCTION     (raw_opcode[3] & 0x3F)
#define DECODE_C0FMT        (DECODE_RS)
#define DECODE_C0FUNC       (DECODE_FUNCTION)
#define DECODE_C1FMT        (DECODE_RS)
#define DECODE_C2TYPE		(DECODE_RD)

#define DECODE_C1BC         (raw_opcode[1] & 0x03)
#define DECODE_C1S          (DECODE_FUNCTION)
#define DECODE_C1D          (DECODE_FUNCTION)
#define DECODE_C1W          (DECODE_FUNCTION)
#define DECODE_C1L          (DECODE_FUNCTION)

#define DECODE_C2IMM		(DECODE_IMMED & 0x07FF)
#define DECODE_C2VEC		(DECODE_SA)

//----------------------------------------------------------------------------------------------------------

void SPECIAL(char *buf);
void RegIMM(char *buf);
void COP0(char *buf);
void COP2(char *buf);
void VECTOP(char *buf);
void Unknown(char *buf);

void J(char *buf);
void JAL(char *buf);
void BEQ(char *buf);
void BNE(char *buf);
void BLEZ(char *buf);
void BGTZ(char *buf);
void ADDI(char *buf);
void ADDIU(char *buf);
void SLTI(char *buf);
void SLTIU(char *buf);
void ANDI(char *buf);
void ORI(char *buf);
void XORI(char *buf);
void LUI(char *buf);
void LB(char *buf);
void LH(char *buf);
void LW(char *buf);
void LBU(char *buf);
void LHU(char *buf);
void SB(char *buf);
void SH(char *buf);
void SW(char *buf);
void LWC2(char *buf);
void SWC2(char *buf);

void SLL(char *buf);
void SRL(char *buf);
void SRA(char *buf);
void SLLV(char *buf);
void SRLV(char *buf);
void SRAV(char *buf);
void JR(char *buf);
void BREAK(char *buf);
void ADD(char *buf);
void ADDU(char *buf);
void SUB(char *buf);
void SUBU(char *buf);
void AND(char *buf);
void OR(char *buf);
void XOR(char *buf);
void NOR(char *buf);
void SLT(char *buf);
void SLTU(char *buf);

void BLTZ(char *buf);
void BGEZ(char *buf);
void BLTZAL(char *buf);
void BGEZAL(char *buf);

void MTC0(char *buf);
void MFC0(char *buf);

void MTC2(char *buf);
void MFC2(char *buf);
void CTC2(char *buf);
void CFC2(char *buf);

void VMULF(char *buf);
void VMULU(char *buf);
void VRNDP(char *buf);
void VMULQ(char *buf);
void VMUDL(char *buf);
void VMUDM(char *buf);
void VMUDN(char *buf);
void VMUDH(char *buf);
void VMACF(char *buf);
void VMACU(char *buf);
void VRNDN(char *buf);
void VMACQ(char *buf);
void VMADL(char *buf);
void VMADM(char *buf);
void VMADN(char *buf);
void VMADH(char *buf);
void VADD(char *buf);
void VSUB(char *buf);
void VSUT(char *buf);
void VABS(char *buf);
void VADDC(char *buf);
void VSUBC(char *buf);
void VADDB(char *buf);
void VSUBB(char *buf);
void VACCB(char *buf);
void VSUCB(char *buf);
void VSAD(char *buf);
void VSAC(char *buf);
void VSUM(char *buf);
void VSAW(char *buf);
void VLT(char *buf);
void VEQ(char *buf);
void VNE(char *buf);
void VGE(char *buf);
void VCL(char *buf);
void VCH(char *buf);
void VCR(char *buf);
void VMRG(char *buf);
void VAND(char *buf);
void VNAND(char *buf);
void VOR(char *buf);
void VNOR(char *buf);
void VXOR(char *buf);
void VNXOR(char *buf);
void VRCP(char *buf);
void VRCPL(char *buf);
void VRCPH(char *buf);
void VMOV(char *buf);
void VRSQ(char *buf);
void VRSQL(char *buf);
void VRSQH(char *buf);
void VNOOP(char *buf);
void VEXTT(char *buf);
void VEXTQ(char *buf);
void VEXTN(char *buf);
void VINST(char *buf);
void VINSQ(char *buf);
void VINSN(char *buf);

//----------------------------------------------------------------------------------------------------------

char *GPR_LUT[32] = {
    "R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3",
    "T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7",
    "S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7",
    "T8", "T9", "K0", "K1", "GP", "SP", "S8", "RA"
};

char *RSP_LUT[32] = {
	"sp_mem_addr", "sp_dram_addr", "sp_rd_len",   "sp_wr_len",  "sp_status", "sp_dma_full", "sp_dma_busy",  "sp_semaphore",
	"dpc_start",   "dpc_end",      "dpc_current", "dpc_status", "dpc_clock", "dpc_bufbusy", "dpc_pipebusy", "dpc_tmem",
	"rsp16",       "rsp17",        "rsp18",       "rsp19",      "rsp20",     "rsp21",       "rsp22",        "rsp23",
	"rsp24",       "rsp25",        "rsp26",       "rsp27",      "rsp28",     "rsp29",       "rsp30",        "rsp31"
};

char *COP2_LUT[32] = {
	"$v0",  "$v1",  "$v2",  "$v3",  "$v4",  "$v5",  "$v6",  "$v7",
	"$v8",  "$v9",  "$v10", "$v11", "$v12", "$v13", "$v14", "$v15",
	"$v16", "$v17", "$v18", "$v19", "$v20", "$v21", "$v22", "$v23",
	"$v24", "$v25", "$v26", "$v27", "$v28", "$v29", "$v30", "$v31"
};

//----------------------------------------------------------------------------------------------------------

void (*Opcode_Table[64])(char *buf) = {
	SPECIAL, RegIMM,  J,       JAL,     BEQ,     BNE,     BLEZ,    BGTZ,
	ADDI,    ADDIU,   SLTI,    SLTIU,   ANDI,    ORI,     XORI,    LUI,
	COP0,    Unknown, COP2,    Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	LB,      LH,      Unknown, LW,      LBU,     LHU,     Unknown, Unknown,
	SB,      SH,      Unknown, SW,      Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, LWC2,    Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, SWC2,    Unknown, Unknown, Unknown, Unknown, Unknown
};

void (*Special_Table[64])(char *buf) = {
	SLL,     Unknown, SRL,     SRA,     SLLV,    Unknown, SRLV,    SRAV,
	JR,      Unknown, Unknown, Unknown, Unknown, BREAK,   Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	ADD,     ADDU,    SUB,     SUBU,    AND,     OR,      XOR,     NOR,
	Unknown, Unknown, SLT,     SLTU,    Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown
};

void (*RegIMM_Table[32])(char *buf) = {
	BLTZ,    BGEZ,    Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	BLTZAL,  BGEZAL,  Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown
};

void (*COP0_Table[32])(char *buf) = {
	MFC0,    Unknown, Unknown, Unknown, MTC0,    Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown
};

void (*COP2_Table[32])(char *buf) = {
	MFC2,    Unknown, CFC2,    Unknown, MTC2,    Unknown, CTC2,    Unknown,
	Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
	VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP, 
	VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP,  VECTOP
};

void (*VectOp_Table[64])(char *buf) = {
	VMULF, VMULU, VRNDP, VMULQ,   VMUDL, VMUDM, VMUDN,   VMUDH,
	VMACF, VMACU, VRNDN, VMACQ,   VMADL, VMADM, VMADN,   VMADH,
	VADD,  VSUB,  VSUT,  VABS,    VADDC, VSUBC, VADDB,   VSUBB,
	VACCB, VSUCB, VSAD,  VSAC,    VSUM,  VSAW,  Unknown, Unknown,
	VLT,   VEQ,   VNE,   VGE,     VCL,   VCH,   VCR,     VMRG,
	VAND,  VNAND, VOR,   VNOR,    VXOR,  VNXOR, Unknown, Unknown,
	VRCP,  VRCPL, VRCPH, VMOV,    VRSQ,  VRSQL, VRSQH,   VNOOP,
	VEXTT, VEXTQ, VEXTN, Unknown, VINST, VINSQ, VINSN,   Unknown
};

#endif
