#pragma once

#include "SPUOpcodes.h"

class SPUThread;

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

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

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

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

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