#pragma once

#include "SPUOpcodes.h"

class SPUThread;

using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t op);

struct spu_interpreter
{
	static void UNK(SPUThread&, spu_opcode_t);
	static void set_interrupt_status(SPUThread&, spu_opcode_t);

	static void STOP(SPUThread&, spu_opcode_t);
	static void LNOP(SPUThread&, spu_opcode_t);
	static void SYNC(SPUThread&, spu_opcode_t);
	static void DSYNC(SPUThread&, spu_opcode_t);
	static void MFSPR(SPUThread&, spu_opcode_t);
	static void RDCH(SPUThread&, spu_opcode_t);
	static void RCHCNT(SPUThread&, spu_opcode_t);
	static void SF(SPUThread&, spu_opcode_t);
	static void OR(SPUThread&, spu_opcode_t);
	static void BG(SPUThread&, spu_opcode_t);
	static void SFH(SPUThread&, spu_opcode_t);
	static void NOR(SPUThread&, spu_opcode_t);
	static void ABSDB(SPUThread&, spu_opcode_t);
	static void ROT(SPUThread&, spu_opcode_t);
	static void ROTM(SPUThread&, spu_opcode_t);
	static void ROTMA(SPUThread&, spu_opcode_t);
	static void SHL(SPUThread&, spu_opcode_t);
	static void ROTH(SPUThread&, spu_opcode_t);
	static void ROTHM(SPUThread&, spu_opcode_t);
	static void ROTMAH(SPUThread&, spu_opcode_t);
	static void SHLH(SPUThread&, spu_opcode_t);
	static void ROTI(SPUThread&, spu_opcode_t);
	static void ROTMI(SPUThread&, spu_opcode_t);
	static void ROTMAI(SPUThread&, spu_opcode_t);
	static void SHLI(SPUThread&, spu_opcode_t);
	static void ROTHI(SPUThread&, spu_opcode_t);
	static void ROTHMI(SPUThread&, spu_opcode_t);
	static void ROTMAHI(SPUThread&, spu_opcode_t);
	static void SHLHI(SPUThread&, spu_opcode_t);
	static void A(SPUThread&, spu_opcode_t);
	static void AND(SPUThread&, spu_opcode_t);
	static void CG(SPUThread&, spu_opcode_t);
	static void AH(SPUThread&, spu_opcode_t);
	static void NAND(SPUThread&, spu_opcode_t);
	static void AVGB(SPUThread&, spu_opcode_t);
	static void MTSPR(SPUThread&, spu_opcode_t);
	static void WRCH(SPUThread&, spu_opcode_t);
	static void BIZ(SPUThread&, spu_opcode_t);
	static void BINZ(SPUThread&, spu_opcode_t);
	static void BIHZ(SPUThread&, spu_opcode_t);
	static void BIHNZ(SPUThread&, spu_opcode_t);
	static void STOPD(SPUThread&, spu_opcode_t);
	static void STQX(SPUThread&, spu_opcode_t);
	static void BI(SPUThread&, spu_opcode_t);
	static void BISL(SPUThread&, spu_opcode_t);
	static void IRET(SPUThread&, spu_opcode_t);
	static void BISLED(SPUThread&, spu_opcode_t);
	static void HBR(SPUThread&, spu_opcode_t);
	static void GB(SPUThread&, spu_opcode_t);
	static void GBH(SPUThread&, spu_opcode_t);
	static void GBB(SPUThread&, spu_opcode_t);
	static void FSM(SPUThread&, spu_opcode_t);
	static void FSMH(SPUThread&, spu_opcode_t);
	static void FSMB(SPUThread&, spu_opcode_t);
	static void LQX(SPUThread&, spu_opcode_t);
	static void ROTQBYBI(SPUThread&, spu_opcode_t);
	static void ROTQMBYBI(SPUThread&, spu_opcode_t);
	static void SHLQBYBI(SPUThread&, spu_opcode_t);
	static void CBX(SPUThread&, spu_opcode_t);
	static void CHX(SPUThread&, spu_opcode_t);
	static void CWX(SPUThread&, spu_opcode_t);
	static void CDX(SPUThread&, spu_opcode_t);
	static void ROTQBI(SPUThread&, spu_opcode_t);
	static void ROTQMBI(SPUThread&, spu_opcode_t);
	static void SHLQBI(SPUThread&, spu_opcode_t);
	static void ROTQBY(SPUThread&, spu_opcode_t);
	static void ROTQMBY(SPUThread&, spu_opcode_t);
	static void SHLQBY(SPUThread&, spu_opcode_t);
	static void ORX(SPUThread&, spu_opcode_t);
	static void CBD(SPUThread&, spu_opcode_t);
	static void CHD(SPUThread&, spu_opcode_t);
	static void CWD(SPUThread&, spu_opcode_t);
	static void CDD(SPUThread&, spu_opcode_t);
	static void ROTQBII(SPUThread&, spu_opcode_t);
	static void ROTQMBII(SPUThread&, spu_opcode_t);
	static void SHLQBII(SPUThread&, spu_opcode_t);
	static void ROTQBYI(SPUThread&, spu_opcode_t);
	static void ROTQMBYI(SPUThread&, spu_opcode_t);
	static void SHLQBYI(SPUThread&, spu_opcode_t);
	static void NOP(SPUThread&, spu_opcode_t);
	static void CGT(SPUThread&, spu_opcode_t);
	static void XOR(SPUThread&, spu_opcode_t);
	static void CGTH(SPUThread&, spu_opcode_t);
	static void EQV(SPUThread&, spu_opcode_t);
	static void CGTB(SPUThread&, spu_opcode_t);
	static void SUMB(SPUThread&, spu_opcode_t);
	static void HGT(SPUThread&, spu_opcode_t);
	static void CLZ(SPUThread&, spu_opcode_t);
	static void XSWD(SPUThread&, spu_opcode_t);
	static void XSHW(SPUThread&, spu_opcode_t);
	static void CNTB(SPUThread&, spu_opcode_t);
	static void XSBH(SPUThread&, spu_opcode_t);
	static void CLGT(SPUThread&, spu_opcode_t);
	static void ANDC(SPUThread&, spu_opcode_t);
	static void CLGTH(SPUThread&, spu_opcode_t);
	static void ORC(SPUThread&, spu_opcode_t);
	static void CLGTB(SPUThread&, spu_opcode_t);
	static void HLGT(SPUThread&, spu_opcode_t);
	static void CEQ(SPUThread&, spu_opcode_t);
	static void MPYHHU(SPUThread&, spu_opcode_t);
	static void ADDX(SPUThread&, spu_opcode_t);
	static void SFX(SPUThread&, spu_opcode_t);
	static void CGX(SPUThread&, spu_opcode_t);
	static void BGX(SPUThread&, spu_opcode_t);
	static void MPYHHA(SPUThread&, spu_opcode_t);
	static void MPYHHAU(SPUThread&, spu_opcode_t);
	static void MPY(SPUThread&, spu_opcode_t);
	static void MPYH(SPUThread&, spu_opcode_t);
	static void MPYHH(SPUThread&, spu_opcode_t);
	static void MPYS(SPUThread&, spu_opcode_t);
	static void CEQH(SPUThread&, spu_opcode_t);
	static void MPYU(SPUThread&, spu_opcode_t);
	static void CEQB(SPUThread&, spu_opcode_t);
	static void HEQ(SPUThread&, spu_opcode_t);
	static void BRZ(SPUThread&, spu_opcode_t);
	static void STQA(SPUThread&, spu_opcode_t);
	static void BRNZ(SPUThread&, spu_opcode_t);
	static void BRHZ(SPUThread&, spu_opcode_t);
	static void BRHNZ(SPUThread&, spu_opcode_t);
	static void STQR(SPUThread&, spu_opcode_t);
	static void BRA(SPUThread&, spu_opcode_t);
	static void LQA(SPUThread&, spu_opcode_t);
	static void BRASL(SPUThread&, spu_opcode_t);
	static void BR(SPUThread&, spu_opcode_t);
	static void FSMBI(SPUThread&, spu_opcode_t);
	static void BRSL(SPUThread&, spu_opcode_t);
	static void LQR(SPUThread&, spu_opcode_t);
	static void IL(SPUThread&, spu_opcode_t);
	static void ILHU(SPUThread&, spu_opcode_t);
	static void ILH(SPUThread&, spu_opcode_t);
	static void IOHL(SPUThread&, spu_opcode_t);
	static void ORI(SPUThread&, spu_opcode_t);
	static void ORHI(SPUThread&, spu_opcode_t);
	static void ORBI(SPUThread&, spu_opcode_t);
	static void SFI(SPUThread&, spu_opcode_t);
	static void SFHI(SPUThread&, spu_opcode_t);
	static void ANDI(SPUThread&, spu_opcode_t);
	static void ANDHI(SPUThread&, spu_opcode_t);
	static void ANDBI(SPUThread&, spu_opcode_t);
	static void AI(SPUThread&, spu_opcode_t);
	static void AHI(SPUThread&, spu_opcode_t);
	static void STQD(SPUThread&, spu_opcode_t);
	static void LQD(SPUThread&, spu_opcode_t);
	static void XORI(SPUThread&, spu_opcode_t);
	static void XORHI(SPUThread&, spu_opcode_t);
	static void XORBI(SPUThread&, spu_opcode_t);
	static void CGTI(SPUThread&, spu_opcode_t);
	static void CGTHI(SPUThread&, spu_opcode_t);
	static void CGTBI(SPUThread&, spu_opcode_t);
	static void HGTI(SPUThread&, spu_opcode_t);
	static void CLGTI(SPUThread&, spu_opcode_t);
	static void CLGTHI(SPUThread&, spu_opcode_t);
	static void CLGTBI(SPUThread&, spu_opcode_t);
	static void HLGTI(SPUThread&, spu_opcode_t);
	static void MPYI(SPUThread&, spu_opcode_t);
	static void MPYUI(SPUThread&, spu_opcode_t);
	static void CEQI(SPUThread&, spu_opcode_t);
	static void CEQHI(SPUThread&, spu_opcode_t);
	static void CEQBI(SPUThread&, spu_opcode_t);
	static void HEQI(SPUThread&, spu_opcode_t);
	static void HBRA(SPUThread&, spu_opcode_t);
	static void HBRR(SPUThread&, spu_opcode_t);
	static void ILA(SPUThread&, spu_opcode_t);
	static void SELB(SPUThread&, spu_opcode_t);
	static void SHUFB(SPUThread&, spu_opcode_t);
	static void MPYA(SPUThread&, spu_opcode_t);
	static void DFCGT(SPUThread&, spu_opcode_t);
	static void DFCMGT(SPUThread&, spu_opcode_t);
	static void DFTSV(SPUThread&, spu_opcode_t);
	static void DFCEQ(SPUThread&, spu_opcode_t);
	static void DFCMEQ(SPUThread&, spu_opcode_t);
};

struct spu_interpreter_fast final : spu_interpreter
{
	static void FREST(SPUThread&, spu_opcode_t);
	static void FRSQEST(SPUThread&, spu_opcode_t);
	static void FCGT(SPUThread&, spu_opcode_t);
	static void FA(SPUThread&, spu_opcode_t);
	static void FS(SPUThread&, spu_opcode_t);
	static void FM(SPUThread&, spu_opcode_t);
	static void FCMGT(SPUThread&, spu_opcode_t);
	static void DFA(SPUThread&, spu_opcode_t);
	static void DFS(SPUThread&, spu_opcode_t);
	static void DFM(SPUThread&, spu_opcode_t);
	static void DFMA(SPUThread&, spu_opcode_t);
	static void DFMS(SPUThread&, spu_opcode_t);
	static void DFNMS(SPUThread&, spu_opcode_t);
	static void DFNMA(SPUThread&, spu_opcode_t);
	static void FSCRRD(SPUThread&, spu_opcode_t);
	static void FESD(SPUThread&, spu_opcode_t);
	static void FRDS(SPUThread&, spu_opcode_t);
	static void FSCRWR(SPUThread&, spu_opcode_t);
	static void FCEQ(SPUThread&, spu_opcode_t);
	static void FCMEQ(SPUThread&, spu_opcode_t);
	static void FI(SPUThread&, spu_opcode_t);
	static void CFLTS(SPUThread&, spu_opcode_t);
	static void CFLTU(SPUThread&, spu_opcode_t);
	static void CSFLT(SPUThread&, spu_opcode_t);
	static void CUFLT(SPUThread&, spu_opcode_t);
	static void FNMS(SPUThread&, spu_opcode_t);
	static void FMA(SPUThread&, spu_opcode_t);
	static void FMS(SPUThread&, spu_opcode_t);
};

struct spu_interpreter_precise final : spu_interpreter
{
	static void FREST(SPUThread&, spu_opcode_t);
	static void FRSQEST(SPUThread&, spu_opcode_t);
	static void FCGT(SPUThread&, spu_opcode_t);
	static void FA(SPUThread&, spu_opcode_t);
	static void FS(SPUThread&, spu_opcode_t);
	static void FM(SPUThread&, spu_opcode_t);
	static void FCMGT(SPUThread&, spu_opcode_t);
	static void DFA(SPUThread&, spu_opcode_t);
	static void DFS(SPUThread&, spu_opcode_t);
	static void DFM(SPUThread&, spu_opcode_t);
	static void DFMA(SPUThread&, spu_opcode_t);
	static void DFMS(SPUThread&, spu_opcode_t);
	static void DFNMS(SPUThread&, spu_opcode_t);
	static void DFNMA(SPUThread&, spu_opcode_t);
	static void FSCRRD(SPUThread&, spu_opcode_t);
	static void FESD(SPUThread&, spu_opcode_t);
	static void FRDS(SPUThread&, spu_opcode_t);
	static void FSCRWR(SPUThread&, spu_opcode_t);
	static void FCEQ(SPUThread&, spu_opcode_t);
	static void FCMEQ(SPUThread&, spu_opcode_t);
	static void FI(SPUThread&, spu_opcode_t);
	static void CFLTS(SPUThread&, spu_opcode_t);
	static void CFLTU(SPUThread&, spu_opcode_t);
	static void CSFLT(SPUThread&, spu_opcode_t);
	static void CUFLT(SPUThread&, spu_opcode_t);
	static void FNMS(SPUThread&, spu_opcode_t);
	static void FMA(SPUThread&, spu_opcode_t);
	static void FMS(SPUThread&, spu_opcode_t);
};
