//
//  Nintendo64 RSP Dissassembler, Copyright (C) 1998 by Michael Tedder
//  ------------------------------------------------------------------
//
//  This proggy dissassembles a raw binary image file to human-readable RSP microcode instructions.
//  Since this program is rather dumb, it makes no attempt to parse an OBJ file for any code
//  records.  Therefore, an "offset" value can be specified to properly align the 4-byte opcodes
//  to be dissassembled.
//
//  This "offset" value, if specified, should be between 1 and 3.  Higher values may be used,
//  however, a simple text editor can trim off any OBJ header garbage that might be interpreted
//  as RSP instructions.  :)
//


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "types.h"
#include "rspdis.h"

int VectorShiftTable[12] = {  0,   1,   2,   3,   4,   4,   3,   3,   4,   4,   4,   4 };
char VectorCodeTable[12] = { 'B', 'S', 'L', 'D', 'Q', 'R', 'P', 'U', 'H', 'F', 'W', 'T'};

uchar raw_opcode[4];
ulong raw_opcode_ulong, raw_opcode_addr;

inline ulong SignExtend16(ushort a)
{
    ulong b;

    __asm {
        push eax
        movsx eax, a
        mov b, eax
        pop eax
    };

    return b;
}

void main(int argc, char *argv[])
{
	FILE *fp;
	ulong offset, temp;
	char buf[128];

	if (argc < 2)
	{
		printf("Usage: RSPDIS <file> [<offset>]\n");
		return;
	}

	offset = 0;
	if (argc == 3) offset = atoi(argv[2]);

	fp = fopen(argv[1], "rb");
	if (fp == NULL)
	{
		printf("Can't open %s!\n", argv[1]);
		return;
	}

	raw_opcode_addr = 0;
	fseek(fp, offset, 0);

	for (;;)
	{
		fread(&temp, 1, 4, fp);
		if (feof(fp))
		{
			fclose(fp);
			return;
		}

		raw_opcode[0] = (uchar)(temp      );
		raw_opcode[1] = (uchar)(temp >>  8);
		raw_opcode[2] = (uchar)(temp >> 16);
		raw_opcode[3] = (uchar)(temp >> 24);
		raw_opcode_ulong = (raw_opcode[0] << 24) | (raw_opcode[1] << 16) | (raw_opcode[2] << 8) | raw_opcode[3];

		Opcode_Table[DECODE_OPCODE](buf);
		printf("%08X  (%02X %02X %02X %02X): %s\n", raw_opcode_addr, raw_opcode[0], raw_opcode[1], raw_opcode[2], 
			raw_opcode[3], buf);

		raw_opcode_addr += 4;
	}
}

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

void SPECIAL(char *buf)
{
	Special_Table[DECODE_FUNCTION](buf);
}

void RegIMM(char *buf)
{
	RegIMM_Table[DECODE_RT](buf);
}

void COP0(char *buf)
{
	COP0_Table[DECODE_RS](buf);
}

void COP2(char *buf)
{
	COP2_Table[DECODE_RS](buf);
}

void VECTOP(char *buf)
{
	VectOp_Table[DECODE_FUNCTION](buf);
}

void Unknown(char *buf)
{ 
	strcpy(buf, "???");
}

// -------------------------------------------------------------------
//
//                       RSP Opcodes
//
// -------------------------------------------------------------------

void J(char *buf)     { sprintf(buf, "J\t0x%08X",			  DECODE_JUMP); }
void JAL(char *buf)   { sprintf(buf, "JAL\t0x%08X",	          DECODE_JUMP); }
void BEQ(char *buf)   { sprintf(buf, "BEQ\t%s, %s, 0x%08X",   GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT], DECODE_OFFSET); }
void BNE(char *buf)   { sprintf(buf, "BNE\t%s, %s, 0x%08X",   GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT], DECODE_OFFSET); }
void BLEZ(char *buf)  { sprintf(buf, "BLEZ\t%s, 0x%08X",      GPR_LUT[DECODE_RS], DECODE_OFFSET); }
void BGTZ(char *buf)  { sprintf(buf, "BGTZ\t%s, 0x%08X",      GPR_LUT[DECODE_RS], DECODE_OFFSET); }
void ADDI(char *buf)  { sprintf(buf, "ADDI\t%s, %s, 0x%04X",  GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void ADDIU(char *buf) { sprintf(buf, "ADDIU\t%s, %s, 0x%04X", GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void SLTI(char *buf)  { sprintf(buf, "SLTI\t%s, %s, 0x%04X",  GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void SLTIU(char *buf) { sprintf(buf, "SLTIU\t%s, %s, 0x%04X", GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void ANDI(char *buf)  { sprintf(buf, "ANDI\t%s, %s, 0x%04X",  GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void ORI(char *buf)   { sprintf(buf, "ORI\t%s, %s, 0x%04X",   GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void XORI(char *buf)  { sprintf(buf, "XORI\t%s, %s, 0x%04X",  GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS], DECODE_IMMED); }
void LUI(char *buf)   { sprintf(buf, "LUI\t%s, 0x%04X",       GPR_LUT[DECODE_RT], DECODE_IMMED); }
void LB(char *buf)    { sprintf(buf, "LB\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void LH(char *buf)    { sprintf(buf, "LH\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void LW(char *buf)    { sprintf(buf, "LW\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void LBU(char *buf)   { sprintf(buf, "LBU\t%s, 0x%04X(%s)",   GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void LHU(char *buf)   { sprintf(buf, "LHU\t%s, 0x%04X(%s)",   GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void SB(char *buf)    { sprintf(buf, "SB\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void SH(char *buf)    { sprintf(buf, "SH\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }
void SW(char *buf)    { sprintf(buf, "SW\t%s, 0x%04X(%s)",    GPR_LUT[DECODE_RT], DECODE_IMMED, GPR_LUT[DECODE_BASE]); }

void LWC2(char *buf)
{ 
	char ch;
	schar ofs;
	slong offset;

	ofs = raw_opcode[3] & 0x7F;
	if (ofs & 0x40) ofs |= 0x80;		// Extend sign bit.
	offset = (slong)ofs << VectorShiftTable[DECODE_C2TYPE];
	ch = VectorCodeTable[DECODE_C2TYPE];

	sprintf(buf, "L%cV\t%s[%d], %d(%s)", ch, COP2_LUT[DECODE_RT], DECODE_SA >> 1, offset, GPR_LUT[DECODE_BASE]);
}

void SWC2(char *buf)
{ 
	char ch;
	schar ofs;
	slong offset;

	ofs = raw_opcode[3] & 0x7F;
	if (ofs & 0x40) ofs |= 0x80;		// Extend sign bit.
	offset = (slong)ofs << VectorShiftTable[DECODE_C2TYPE];
	ch = VectorCodeTable[DECODE_C2TYPE];

	sprintf(buf, "S%cV\t%s[%d], %d(%s)", ch, COP2_LUT[DECODE_RT], DECODE_SA >> 1, offset, GPR_LUT[DECODE_BASE]);
}

// -------------------------------------------------------------------
//
//                       Special Opcodes
//
// -------------------------------------------------------------------

void SLL(char *buf)
{
    if (raw_opcode_ulong == 0x00000000)
        strcpy(buf, "NOP");
    else
        sprintf(buf, "SLL\t%s, %s, 0x%02X", GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], DECODE_SA);
}

void SRL(char *buf)   { sprintf(buf, "SRL\t%s, %s, 0x%02X", GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], DECODE_SA); }
void SRA(char *buf)   { sprintf(buf, "SRA\t%s, %s, 0x%02X", GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], DECODE_SA); }
void SLLV(char *buf)  { sprintf(buf, "SLLV\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS]); }
void SRLV(char *buf)  { sprintf(buf, "SRLV\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS]); }
void SRAV(char *buf)  { sprintf(buf, "SRAV\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RT], GPR_LUT[DECODE_RS]); }
void JR(char *buf)    { sprintf(buf, "JR\t%s",              GPR_LUT[DECODE_RS]); }
void BREAK(char *buf) { sprintf(buf, "BREAK\t0x%05X",       DECODE_BREAK); }
void ADD(char *buf)   { sprintf(buf, "ADD\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void ADDU(char *buf)  { sprintf(buf, "ADDU\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void SUB(char *buf)   { sprintf(buf, "SUB\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void SUBU(char *buf)  { sprintf(buf, "SUBU\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void AND(char *buf)   { sprintf(buf, "AND\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void OR(char *buf)    { sprintf(buf, "OR\t%s, %s, %s",      GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void XOR(char *buf)   { sprintf(buf, "XOR\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void NOR(char *buf)   { sprintf(buf, "NOR\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void SLT(char *buf)   { sprintf(buf, "SLT\t%s, %s, %s",     GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }
void SLTU(char *buf)  { sprintf(buf, "SLTU\t%s, %s, %s",    GPR_LUT[DECODE_RD], GPR_LUT[DECODE_RS], GPR_LUT[DECODE_RT]); }

// -------------------------------------------------------------------
//
//                       REGIMM Opcodes
//
// -------------------------------------------------------------------

void BLTZ(char *buf)   { sprintf(buf, "BLTZ\t%s, 0x%08X",   GPR_LUT[DECODE_RS], DECODE_OFFSET); }
void BGEZ(char *buf)   { sprintf(buf, "BGEZ\t%s, 0x%08X",   GPR_LUT[DECODE_RS], DECODE_OFFSET); }
void BLTZAL(char *buf) { sprintf(buf, "BLTZAL\t%s, 0x%08X", GPR_LUT[DECODE_RS], DECODE_OFFSET); }
void BGEZAL(char *buf) { sprintf(buf, "BGEZAL\t%s, 0x%08X", GPR_LUT[DECODE_RS], DECODE_OFFSET); }

// -------------------------------------------------------------------
//
//                          COP0 Opcodes
//
// -------------------------------------------------------------------

void MTC0(char *buf) { sprintf(buf, "MTC0\t%s, %s", GPR_LUT[DECODE_RT], RSP_LUT[DECODE_FS]); }
void MFC0(char *buf) { sprintf(buf, "MFC0\t%s, %s", GPR_LUT[DECODE_RT], RSP_LUT[DECODE_FS]); }

// -------------------------------------------------------------------
//
//                          COP2 Opcodes
//
// -------------------------------------------------------------------

void MTC2(char *buf) { sprintf(buf, "MTC2\t%s, %s[%d]",   GPR_LUT[DECODE_RT], COP2_LUT[DECODE_FS], (DECODE_SA >> 1) & 0x0F); }
void MFC2(char *buf) { sprintf(buf, "MFC2\t%s, %s[%d]",   GPR_LUT[DECODE_RT], COP2_LUT[DECODE_FS], (DECODE_SA >> 1) & 0x0F); }
void CTC2(char *buf) { sprintf(buf, "CTC2\t%s, flag[%d]", GPR_LUT[DECODE_RT], DECODE_RD & 0x03); }
void CFC2(char *buf) { sprintf(buf, "CFC2\t%s, flag[%d]", GPR_LUT[DECODE_RT], DECODE_RD & 0x03); }

// -------------------------------------------------------------------
//
//                         Vector Opcodes
//
// -------------------------------------------------------------------

void VectorOp(char *buf, char *op)
{
	switch (DECODE_RS & 0x0F)
	{
		case 0x00: sprintf(buf, "%s\t%s, %s, %s",     op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x01: sprintf(buf, "%s ???",             op);
		case 0x02: sprintf(buf, "%s\t%s, %s, %s[0q]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x03: sprintf(buf, "%s\t%s, %s, %s[1q]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x04: sprintf(buf, "%s\t%s, %s, %s[0h]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x05: sprintf(buf, "%s\t%s, %s, %s[1h]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x06: sprintf(buf, "%s\t%s, %s, %s[2h]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x07: sprintf(buf, "%s\t%s, %s, %s[3h]", op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x08: sprintf(buf, "%s\t%s, %s, %s[0]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x09: sprintf(buf, "%s\t%s, %s, %s[1]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0A: sprintf(buf, "%s\t%s, %s, %s[2]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0B: sprintf(buf, "%s\t%s, %s, %s[3]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0C: sprintf(buf, "%s\t%s, %s, %s[4]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0D: sprintf(buf, "%s\t%s, %s, %s[5]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0E: sprintf(buf, "%s\t%s, %s, %s[6]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
		case 0x0F: sprintf(buf, "%s\t%s, %s, %s[7]",  op, COP2_LUT[DECODE_C2VEC], COP2_LUT[DECODE_RD], COP2_LUT[DECODE_RT]); break;
	}
}

void VMULF(char *buf) { VectorOp(buf, "VMULF"); }
void VMULU(char *buf) { VectorOp(buf, "VMULU"); }
void VRNDP(char *buf) { VectorOp(buf, "VRNDP"); }
void VMULQ(char *buf) { VectorOp(buf, "VMULQ"); }
void VMUDL(char *buf) { VectorOp(buf, "VMUDL"); }
void VMUDM(char *buf) { VectorOp(buf, "VMUDM"); }
void VMUDN(char *buf) { VectorOp(buf, "VMUDN"); }
void VMUDH(char *buf) { VectorOp(buf, "VMUDH"); }
void VMACF(char *buf) { VectorOp(buf, "VMACF"); }
void VMACU(char *buf) { VectorOp(buf, "VMACU"); }
void VRNDN(char *buf) { VectorOp(buf, "VRNDN"); }
void VMACQ(char *buf) { VectorOp(buf, "VMACQ"); }
void VMADL(char *buf) { VectorOp(buf, "VMADL"); }
void VMADM(char *buf) { VectorOp(buf, "VMADM"); }
void VMADN(char *buf) { VectorOp(buf, "VMADN"); }
void VMADH(char *buf) { VectorOp(buf, "VMADH"); }
void VADD(char *buf)  { VectorOp(buf, "VADD"); }
void VSUB(char *buf)  { VectorOp(buf, "VSUB"); }
void VSUT(char *buf)  { VectorOp(buf, "VSUT"); }
void VABS(char *buf)  { VectorOp(buf, "VABS"); }
void VADDC(char *buf) { VectorOp(buf, "VADDC"); }
void VSUBC(char *buf) { VectorOp(buf, "VSUBC"); }
void VADDB(char *buf) { VectorOp(buf, "VADDB"); }
void VSUBB(char *buf) { VectorOp(buf, "VSUBB"); }
void VACCB(char *buf) { VectorOp(buf, "VACCB"); }
void VSUCB(char *buf) { VectorOp(buf, "VSUCB"); }
void VSAD(char *buf)  { VectorOp(buf, "VSAD"); }
void VSAC(char *buf)  { VectorOp(buf, "VSAC"); }
void VSUM(char *buf)  { VectorOp(buf, "VSUM"); }
void VSAW(char *buf)  { VectorOp(buf, "VSAW"); }
void VLT(char *buf)   { VectorOp(buf, "VLT"); }
void VEQ(char *buf)   { VectorOp(buf, "VEQ"); }
void VNE(char *buf)   { VectorOp(buf, "VNE"); }
void VGE(char *buf)   { VectorOp(buf, "VGE"); }
void VCL(char *buf)   { VectorOp(buf, "VCL"); }
void VCH(char *buf)   { VectorOp(buf, "VCH"); }
void VCR(char *buf)   { VectorOp(buf, "VCR"); }
void VMRG(char *buf)  { VectorOp(buf, "VMRG"); }
void VAND(char *buf)  { VectorOp(buf, "VAND"); }
void VNAND(char *buf) { VectorOp(buf, "VNAND"); }
void VOR(char *buf)   { VectorOp(buf, "VOR"); }
void VNOR(char *buf)  { VectorOp(buf, "VNOR"); }
void VXOR(char *buf)  { VectorOp(buf, "VXOR"); }
void VNXOR(char *buf) { VectorOp(buf, "VNXOR"); }
void VRCP(char *buf)  { sprintf(buf, "VRCP\t%s[%d], %s[%d]",  COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VRCPL(char *buf) { sprintf(buf, "VRCPL\t%s[%d], %s[%d]", COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VRCPH(char *buf) { sprintf(buf, "VRCPH\t%s[%d], %s[%d]", COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VMOV(char *buf)  { sprintf(buf, "VMOV\t%s[%d], %s[%d]",  COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VRSQ(char *buf)  { sprintf(buf, "VRSQ\t%s[%d], %s[%d]",  COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VRSQL(char *buf) { sprintf(buf, "VRSQL\t%s[%d], %s[%d]", COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VRSQH(char *buf) { sprintf(buf, "VRSQH\t%s[%d], %s[%d]", COP2_LUT[DECODE_C2VEC], DECODE_RD & 0x07, COP2_LUT[DECODE_RT], DECODE_RS & 0x07); }
void VNOOP(char *buf) { VectorOp(buf, "VNOOP"); }
void VEXTT(char *buf) { VectorOp(buf, "VEXTT"); }
void VEXTQ(char *buf) { VectorOp(buf, "VEXTQ"); }
void VEXTN(char *buf) { VectorOp(buf, "VEXTN"); }
void VINST(char *buf) { VectorOp(buf, "VINST"); }
void VINSQ(char *buf) { VectorOp(buf, "VINSQ"); }
void VINSN(char *buf) { VectorOp(buf, "VINSN"); }
