#pragma once

// SPU Instruction Type
struct spu_itype
{
	enum
	{
		memory   = 1 << 8,  // Memory Load/Store Instructions
		constant = 1 << 9,  // Constant Formation Instructions
		integer  = 1 << 10, // Integer and Logical Instructions
		shiftrot = 1 << 11, // Shift and Rotate Instructions
		compare  = 1 << 12, // Compare Instructions
		branch   = 1 << 13, // Branch Instructions
		floating = 1 << 14, // Floating-Point Instructions

		_quadrop = 1 << 15, // 4-op Instructions
	};

	enum type
	{
		UNK = 0,

		HEQ,
		HEQI,
		HGT,
		HGTI,
		HLGT,
		HLGTI,

		HBR,
		HBRA,
		HBRR,

		STOP,
		STOPD,
		LNOP,
		NOP,
		SYNC,
		DSYNC,
		MFSPR,
		MTSPR,
		RDCH,
		RCHCNT,
		WRCH,

		LQD = memory,
		LQX,
		LQA,
		LQR,
		STQD,
		STQX,
		STQA,
		STQR,

		CBD = constant,
		CBX,
		CHD,
		CHX,
		CWD,
		CWX,
		CDD,
		CDX,
		ILH,
		ILHU,
		IL,
		ILA,
		IOHL,
		FSMBI,

		AH = integer,
		AHI,
		A,
		AI,
		SFH,
		SFHI,
		SF,
		SFI,
		ADDX,
		CG,
		CGX,
		SFX,
		BG,
		BGX,
		MPY,
		MPYU,
		MPYI,
		MPYUI,
		MPYH,
		MPYS,
		MPYHH,
		MPYHHA,
		MPYHHU,
		MPYHHAU,
		CLZ,
		CNTB,
		FSMB,
		FSMH,
		FSM,
		GBB,
		GBH,
		GB,
		AVGB,
		ABSDB,
		SUMB,
		XSBH,
		XSHW,
		XSWD,
		AND,
		ANDC,
		ANDBI,
		ANDHI,
		ANDI,
		OR,
		ORC,
		ORBI,
		ORHI,
		ORI,
		ORX,
		XOR,
		XORBI,
		XORHI,
		XORI,
		NAND,
		NOR,
		EQV,

		MPYA = integer | _quadrop,
		SELB,
		SHUFB,

		SHLH = shiftrot,
		SHLHI,
		SHL,
		SHLI,
		SHLQBI,
		SHLQBII,
		SHLQBY,
		SHLQBYI,
		SHLQBYBI,
		ROTH,
		ROTHI,
		ROT,
		ROTI,
		ROTQBY,
		ROTQBYI,
		ROTQBYBI,
		ROTQBI,
		ROTQBII,
		ROTHM,
		ROTHMI,
		ROTM,
		ROTMI,
		ROTQMBY,
		ROTQMBYI,
		ROTQMBYBI,
		ROTQMBI,
		ROTQMBII,
		ROTMAH,
		ROTMAHI,
		ROTMA,
		ROTMAI,

		CEQB = compare,
		CEQBI,
		CEQH,
		CEQHI,
		CEQ,
		CEQI,
		CGTB,
		CGTBI,
		CGTH,
		CGTHI,
		CGT,
		CGTI,
		CLGTB,
		CLGTBI,
		CLGTH,
		CLGTHI,
		CLGT,
		CLGTI,

		BR = branch,
		BRA,
		BRSL,
		BRASL,
		BI,
		IRET,
		BISLED,
		BISL,
		BRNZ,
		BRZ,
		BRHNZ,
		BRHZ,
		BIZ,
		BINZ,
		BIHZ,
		BIHNZ,

		FA = floating,
		DFA,
		FS,
		DFS,
		FM,
		DFM,
		DFMA,
		DFNMS,
		DFMS,
		DFNMA,
		FREST,
		FRSQEST,
		FI,
		CSFLT,
		CFLTS,
		CUFLT,
		CFLTU,
		FRDS,
		FESD,
		FCEQ,
		FCMEQ,
		FCGT,
		FCMGT,
		FSCRWR,
		FSCRRD,

		DFCEQ,
		DFCMEQ,
		DFCGT,
		DFCMGT,
		DFTSV,

		FMA = floating | _quadrop,
		FNMS,
		FMS,
	};

	// Enable address-of operator for spu_decoder<>
	friend constexpr type operator &(type value)
	{
		return value;
	}
};

// Encode instruction name: 6 bits per character (0x20..0x5f), max 10
static constexpr u64 spu_iname_encode(const char* ptr, u64 value = 0)
{
	return *ptr == '\0' ? value : spu_iname_encode(ptr + 1, (*ptr - 0x20) | (value << 6));
}

#define NAME(x) x = spu_iname_encode(#x)

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

	// Enable address-of operator for spu_decoder<>
	friend constexpr type operator &(type value)
	{
		return value;
	}
};

#undef NAME
