/*
Copyright (C) 2006 Evan Teran
                   eteran@alum.rit.edu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef INSTRUCTION_20070427_H_
#define INSTRUCTION_20070427_H_

#include <stdint.h>	// for [u]int[n]_t types
#include <cstddef>	// for std::size_t
#include <new>

#include "Operand.h"

class ModRM;
class SIB;

struct invalid_instruction : public std::exception {
public:
	invalid_instruction(std::size_t size) :  m_Size(size) { }
	std::size_t size() const { return m_Size; }
private:
	std::size_t m_Size;
};

struct instruction_too_big	: public invalid_instruction { instruction_too_big(std::size_t size)	: invalid_instruction(size) {} };
struct invalid_operand		: public invalid_instruction { invalid_operand(std::size_t size)		: invalid_instruction(size) {} };
struct too_many_operands	: public invalid_instruction { too_many_operands(std::size_t size)		: invalid_instruction(size) {} };
#define BOUNDS_CHECK(new_size, max_size) do { if((new_size) > (max_size)) { throw instruction_too_big(Instruction::size()); } } while(0)

#define UNUSED(x) (void)(x)

class Instruction {
public:
	typedef unsigned int uint_t;
	
public:
	static const int MAX_SIZE		= 20;
	static const int MAX_OPERANDS	= 3;
	
public:
	enum Mode {
		MODE_16BIT,
		MODE_32BIT,
		MODE_64BIT
	};

	Instruction(const uint8_t *buf, std::size_t size, uint64_t rva, const std::nothrow_t&, Mode mode = MODE_32BIT) throw();
	Instruction(const uint8_t *buf, std::size_t size, uint64_t rva, Mode mode = MODE_32BIT);

private:
	void initialize(const uint8_t *buf, std::size_t size);
	
public:
	enum Prefix {
		PREFIX_LOCK				= 0x00000001,
		PREFIX_REPNE			= 0x00000002,
		PREFIX_REP				= 0x00000004,

		PREFIX_CS				= 0x00000100,
		PREFIX_SS				= 0x00000200,
		PREFIX_DS				= 0x00000400,
		PREFIX_ES				= 0x00000800,
		PREFIX_FS				= 0x00001000,
		PREFIX_GS				= 0x00002000,
		PREFIX_BRANCH_NOT_TAKEN	= 0x00004000,
		PREFIX_BRANCH_TAKEN		= 0x00008000,

		PREFIX_OPERAND			= 0x00010000,

		PREFIX_ADDRESS			= 0x01000000
	};
	
	enum Type {
		/* invalid */
		OP_INVALID		= 0x00000000,

		/* data transfer */
		OP_MOV,
		OP_CMOVCC,
		OP_XCHG,
		OP_BSWAP,
		OP_XADD,
		OP_CMPXCHG,
		OP_PUSH,
		OP_PUSHA,
		OP_POP,
		OP_POPA,
		OP_CWD,
		OP_CDQ,
		OP_CBW,
		OP_CWDE,
		OP_MOVSX,
		OP_MOVZX,

		/* arithmetic */
		OP_ADD,
		OP_ADC,
		OP_SUB,
		OP_SBB,
		OP_IMUL,
		OP_MUL,
		OP_IDIV,
		OP_DIV,
		OP_INC,
		OP_DEC,
		OP_NEG,
		OP_CMP,
		OP_DAA,
		OP_DAS,
		OP_AAA,
		OP_AAS,
		OP_AAM,
		OP_AAD,

		/* logic */
		OP_AND,
		OP_OR,
		OP_XOR,
		OP_NOT,

		/* shift/rotate */
		OP_SAR,
		OP_SHR,
		OP_SHL,
		OP_SHRD,
		OP_SHLD,
		OP_ROR,
		OP_ROL,
		OP_RCR,
		OP_RCL,

		/* bit/byte */
		OP_BT,
		OP_BTS,
		OP_BTR,
		OP_BTC,
		OP_BSF,
		OP_BSR,
		OP_SETCC,
		OP_TEST,

		/* control flow */
		OP_JMP,
		OP_JCC,
		OP_LOOP,
		OP_LOOPE,
		OP_LOOPNE,
		OP_CALL,
		OP_RET,
		OP_IRET,
		OP_INT,
		OP_INT3,
		OP_INTO,
		OP_BOUND,
		OP_ENTER,
		OP_LEAVE,

		/* string */
		OP_MOVS,
		OP_CMPS,
		OP_CMPSW,
		OP_SCAS,
		OP_LODS,
		OP_STOS,

		/* I/O */
		OP_IN,
		OP_OUT,
		OP_INS,
		OP_OUTS,

		/* flag control */
		OP_STC,
		OP_CLC,
		OP_CMC,
		OP_CLD,
		OP_STD,
		OP_LAHF,
		OP_SAHF,
		OP_PUSHF,
		OP_POPF,
		OP_STI,
		OP_CLI,

		/* segment manipulation */
		OP_LDS,
		OP_LES,
		OP_LFS,
		OP_LGS,
		OP_LSS,

		/* misc */
		OP_LEA,
		OP_NOP,
		OP_UD,
		OP_UD2,
		OP_XLAT,
		OP_CPUID,

		/* misc */
		OP_CMPXCH8B,
		OP_MOVNTSD,
		OP_MOVNTSS,

		/* VM */
		OP_VMCALL,
		OP_VMCLEAR,
		OP_VMLAUNCH,
		OP_VMPTRLD,
		OP_VMPTRST,
		OP_VMRESUME,
		OP_VMXOFF,
		OP_VMXON,
		OP_VMREAD,
		OP_VMWRITE,

		/* system */
		OP_LGDT,
		OP_SGDT,
		OP_LLDT,
		OP_SLDT,
		OP_LTR,
		OP_STR,
		OP_LIDT,
		OP_SIDT,
		OP_LMSW,
		OP_SMSW,
		OP_CLTS,
		OP_ARPL,
		OP_LAR,
		OP_LSL,
		OP_VERR,
		OP_VERW,
		OP_INVD,
		OP_WBINVD,
		OP_INVLPG,		
		OP_HLT,
		OP_RSM,
		OP_RDMSR,
		OP_WRMSR,
		OP_RDPMC,
		OP_RDTSC,
		OP_SYSENTER,
		OP_SYSEXIT,

		/* MMX */
		OP_MOVD,
		OP_MOVQ,
		OP_PACKSSDW,
		OP_PACKSSWB,
		OP_PACKUSWB,
		OP_PUNPCKHBW,
		OP_PUNPCKHWD,
		OP_PUNPCKHDQ,
		OP_PUNPCKLBW,
		OP_PUNPCKLWD,
		OP_PUNPCKLDQ,
		OP_PADDB,
		OP_PADDW,
		OP_PADDD,
		OP_PABSD,	/* intel says this is both MMX and SSSE3! */
		OP_PADDSB,
		OP_PADDSW,
		OP_PADDUSB,
		OP_PADDUSW,
		OP_PSUBB,
		OP_PSUBW,
		OP_PSUBD,
		OP_PSUBSB,
		OP_PSUBSW,
		OP_PSUBUSB,
		OP_PSUBUSW,
		OP_PMULHW,
		OP_PMULLW,
		OP_PMADDWD,
		OP_PCMPEQB,
		OP_PCMPEQW,
		OP_PCMPEQD,
		OP_PCMPGTB,
		OP_PCMPGTW,
		OP_PCMPGTD,
		OP_PAND,
		OP_PANDN,
		OP_POR,
		OP_PXOR,
		OP_PSLLW,
		OP_PSLLD,
		OP_PSLLQ,
		OP_PSRLW,
		OP_PSRLD,
		OP_PSRLQ,
		OP_PSRAW,
		OP_PSRAD,
		OP_EMMS,

		/* SSE */
		OP_MOVAPS,
		OP_MOVUPS,
		OP_MOVHPS,
		// TODO: MOVHLPS? where is it?
		OP_MOVLPS,
		// TODO: MOVLHPS? where is it?
		OP_MOVMSKPS,
		OP_MOVSS,
		OP_ADDPS,
		OP_ADDSS,
		OP_SUBPS,
		OP_SUBSS,
		OP_MULPS,
		OP_MULSS,
		OP_DIVPS,
		OP_DIVSS,
		OP_RCPPS,
		OP_RCPSS,
		OP_SQRTPS,
		OP_SQRTSS,
		OP_RSQRTPS,
		OP_RSQRTSS,
		OP_MAXPS,
		OP_MAXSS,
		OP_MINPS,
		OP_MINSS,
		OP_CMPPS,
		OP_CMPSS,
		OP_COMISS,
		OP_UCOMISS,
		OP_ANDPS,
		OP_ANDNPS,
		OP_ORPS,
		OP_XORPS,
		OP_SHUFPS,
		OP_UNPCKHPS,
		OP_UNPCKLPS,
		OP_CVTPI2PS,
		OP_CVTSI2SS,
		OP_CVTPS2PI,
		OP_CVTTPS2PI,
		OP_CVTSS2SI,
		OP_CVTTSS2SI,
		OP_LDMXCSR,
		OP_STMXCSR,
		OP_PAVGB,
		OP_PAVGW,
		OP_PEXTRW,
		OP_PINSRW,
		OP_PMAXUB,
		OP_PMAXSW,
		OP_PMINUB,
		OP_PMINSW,
		OP_PMOVMSKB,
		OP_PMULHUW,
		OP_PSADBW,
		OP_PSHUFW,
		OP_MASKMOVQ,
		OP_MOVNTQ,
		OP_MOVNTPS,
		OP_PREFETCHH,
		OP_SFENCE,

		/* SSE2 */
		OP_MOVAPD,
		OP_MOVUPD,
		OP_MOVHPD,
		OP_MOVLPD,
		OP_MOVMSKPD,
		OP_MOVSD,
		OP_ADDPD,
		OP_ADDSD,
		OP_SUBPD,
		OP_SUBSD,
		OP_MULPD,
		OP_MULSD,
		OP_DIVPD,
		OP_DIVSD,
		OP_SQRTPD,
		OP_SQRTSD,
		OP_MAXPD,
		OP_MAXSD,
		OP_MINPD,
		OP_MINSD,
		OP_ANDPD,
		OP_ANDNPD,
		OP_ORPD,
		OP_XORPD,
		OP_CMPPD,
		OP_CMPSD,
		OP_COMISD,
		OP_UCOMISD,
		OP_SHUFPD,
		OP_UNPCKHPD,
		OP_UNPCKLPD,
		OP_CVTPD2PI,
		OP_CVTTPD2PI,
		OP_CVTPI2PD,
		OP_CVTPD2DQ,
		OP_CVTTPD2DQ,
		OP_CVTDQ2PD,
		OP_CVTPS2PD,
		OP_CVTPD2PS,
		OP_CVTSS2SD,
		OP_CVTSD2SS,
		OP_CVTSD2SI,
		OP_CVTTSD2SI,
		OP_CVTSI2SD,
		OP_CVTDQ2PS,
		OP_CVTPS2DQ,
		OP_CVTTPS2DQ,
		OP_MOVDQA,
		OP_MOVDQU,
		OP_MOVQ2DQ,
		OP_MOVDQ2Q,
		OP_PMULUDQ,
		OP_PADDQ,
		OP_PSUBQ,
		OP_PSHUFLW,
		OP_PSHUFHW,
		OP_PSHUFD,
		OP_PSLLDQ,
		OP_PSRLDQ,
		OP_PUNPCKHQDQ,
		OP_PUNPCKLQDQ,
		OP_CLFLUSH,
		OP_LFENCE,
		OP_MFENCE,
		OP_PAUSE,
		OP_MASKMOVDQU,
		OP_MOVNTPD,
		OP_MOVNTDQ,
		OP_MOVNTI,

		/* SSE3 */
		OP_FISTTP,
		OP_LDDQU,
		OP_ADDSUBPS,   
		OP_ADDSUBPD,
		OP_HADDPS,
		OP_HSUBPS,
		OP_HADDPD,
		OP_HSUBPD,
		OP_MOVSHDUP,
		OP_MOVSLDUP,
		OP_MOVDDUP,
		OP_MONITOR,
		OP_MWAIT,

		/* SSSE3 */
		OP_PHADDW,
		OP_PHADDSW,
		OP_PHADDD,
		OP_PHSUBW,
		OP_PHSUBSW,
		OP_PHSUBD,
		OP_PABSB,
		OP_PABSW,
		OP_PMADDUBSW,
		OP_PMULHRSW,
		OP_PSHUFB,
		OP_PSIGNB,
		OP_PSIGNW,
		OP_PSIGND,
		OP_PALIGNR,

		/* FPU ops */
		OP_F2XM1,
		OP_FABS,
		OP_FADD,
		OP_FADDP,
		OP_FBLD,
		OP_FBSTP,
		OP_FCHS,
		OP_FCLEX,
		OP_FCMOVB,
		OP_FCMOVBE,
		OP_FCMOVE,
		OP_FCMOVNB,
		OP_FCMOVNBE,
		OP_FCMOVNE,
		OP_FCMOVNU,
		OP_FCMOVU,
		OP_FCOM,
		OP_FCOMI,
		OP_FCOMIP,
		OP_FCOMP,
		OP_FCOMPP,
		OP_FCOS,
		OP_FDECSTP,
		OP_FDIV,
		OP_FDIVP,
		OP_FDIVR,
		OP_FDIVRP,
		OP_FFREE,
		OP_FIADD,
		OP_FICOM,
		OP_FICOMP,
		OP_FIDIV,
		OP_FIDIVR,
		OP_FILD,
		OP_FIMUL,
		OP_FINCSTP,
		OP_FINIT,
		OP_FIST,
		OP_FISTP,
		OP_FISUB,
		OP_FISUBR,
		OP_FLD,
		OP_FLD1,
		OP_FLDCW,
		OP_FLDENV,
		OP_FLDL2E,
		OP_FLDL2T,
		OP_FLDLG2,
		OP_FLDLN2,
		OP_FLDPI,
		OP_FLDZ,
		OP_FMUL,
		OP_FMULP,
		OP_FNOP,
		OP_FPATAN,
		OP_FPREM,
		OP_FPREM1,
		OP_FPTAN,
		OP_FPXTRACT,
		OP_FRNDINT,
		OP_FRSTOR,
		OP_FSAVE,
		OP_FSCALE,
		OP_FSIN,
		OP_FSINCOS,
		OP_FSQRT,
		OP_FST,
		OP_FSTCW,
		OP_FSTENV,
		OP_FSTP,
		OP_FSTSW,
		OP_FSUB,
		OP_FSUBP,
		OP_FSUBR,
		OP_FSUBRP,
		OP_FTST,
		OP_FUCOM,
		OP_FUCOMI,
		OP_FUCOMIP,
		OP_FUCOMP,
		OP_FUCOMPP,
		OP_FXAM,
		OP_FXCH,
		OP_FXRSTOR,
		OP_FXSAVE,
		OP_FYL2XP1,
		OP_FYLSX,
		OP_WAIT,

		/* these aren't really valid, should never been seen in any external API */		
		OP_GROUP1,
		OP_GROUP2,
		OP_GROUP3,
		OP_GROUP4,
		OP_GROUP5,
		OP_GROUP6,
		OP_GROUP7,
		OP_GROUP8,
		OP_GROUP9,
		OP_GROUP10,
		OP_GROUP11,
		OP_GROUP12,
		OP_GROUP13,
		OP_GROUP14,
		OP_GROUP15,
		OP_GROUP16,
		OP_GROUP17,
		OP_PREFIX,
		OP_2BYTE,
		OP_3BYTE,
		OP_FPU,
	};

private:
	void processPrefixes(const uint8_t *&buf, std::size_t size);
	Operand &nextOperand();
		
private:
	typedef void (Instruction::*DecoderFunction)(const uint8_t *);
	
	// convinience binders,	
	template<DecoderFunction F1, DecoderFunction F2, DecoderFunction F3>
	void decode(const uint8_t *buf);
	
	template<DecoderFunction F1, DecoderFunction F2>
	void decode(const uint8_t *buf);
	
	template<DecoderFunction F1>
	void decode(const uint8_t *buf);
	
	void decode(const uint8_t *buf);
	
private:
	// special cased names
	void decode_cwde_cbw(const uint8_t *buf);
	void decode_cdq_cwd(const uint8_t *buf);
	void decode_pushfd_pushfw(const uint8_t *buf);
	void decode_popfd_popfw(const uint8_t *buf);
	void decode_movsd_movsw(const uint8_t *buf);
	void decode_cmpsd_cmpsw(const uint8_t *buf);
	void decode_stosd_stosw(const uint8_t *buf);
	void decode_lodsd_lodsw(const uint8_t *buf);
	void decode_scasd_scasw(const uint8_t *buf);
	void decode_iret_iretw(const uint8_t *buf);
	void decode_nop_pause(const uint8_t *buf);
	void decode_outsd_outsw(const uint8_t *buf);
	void decode_insd_insw(const uint8_t *buf);
	
	void decode_pushad_pushaw(const uint8_t *buf);
	void decode_popad_popaw(const uint8_t *buf);

private:
	// groups
	void decode_group1(const uint8_t *buf);
	void decode_group2(const uint8_t *buf);
	void decode_group2D(const uint8_t *buf);
	void decode_group3(const uint8_t *buf);
	void decode_group4(const uint8_t *buf);
	void decode_group5(const uint8_t *buf);
	void decode_group6(const uint8_t *buf);
	void decode_group7(const uint8_t *buf);
	void decode_group8(const uint8_t *buf);
	void decode_group9(const uint8_t *buf);
	void decode_group10(const uint8_t *buf);
	void decode_group11(const uint8_t *buf);
	void decode_group12(const uint8_t *buf);
	void decode_group13(const uint8_t *buf);
	void decode_group14(const uint8_t *buf);
	void decode_group15(const uint8_t *buf);
	void decode_group16(const uint8_t *buf);
	void decode_group17(const uint8_t *buf);
	
private:
	// invalid handler
	void decode_invalid(const uint8_t *buf);
	
private:
	// multibyte encodings
	void decode_x87(const uint8_t *buf);
	void decode_2byte(const uint8_t *buf);
	void decode_3byte_38(const uint8_t *buf);
	void decode_3byte_3A(const uint8_t *buf);

private:	
	template<Operand::Register REG>
	void decode_Reg(const uint8_t *buf);

	template<int64_t IMM>
	void decode_const_Iq(const uint8_t *buf);
	
	template<int32_t IMM>
	void decode_const_Id(const uint8_t *buf);
	
	template<int16_t IMM>
	void decode_const_Iw(const uint8_t *buf);
	
	template<int8_t IMM>
	void decode_const_Ib(const uint8_t *buf);
	
	template<typename T>
	T getImmidiate(const uint8_t *buf);
	
	template<typename T>
	T getDisplacement(const uint8_t *buf);
	
	template<int index>
	void decode_STi(const uint8_t *buf);
	
	template<Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_Gx(const uint8_t *buf);

	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_0_16(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_1_16(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_2_16(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_0_32(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_1_32(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_2_32(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_3_32(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_Invalid(const uint8_t *buf, const ModRM &rm, Operand &operand);
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_Ex(const uint8_t *buf);
	
private:
	// ModRM Reg or Memory 
	void decode_Ev(const uint8_t *buf);
	void decode_Eb(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION8, indexToReg8>(buf); }
	void decode_Ew(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg16>(buf); }
	void decode_Ed(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf); }
	void decode_Eq(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToReg64>(buf); }
	void decode_Qd(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegMMX>(buf); }
	void decode_Qq(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegMMX>(buf); }
	void decode_Qo(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION128, indexToRegMMX>(buf); }   
	void decode_Wd(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegXMMX>(buf); }   
	void decode_Wq(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegXMMX>(buf); }
	void decode_Wo(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION128, indexToRegXMMX>(buf); }


	// special case for SMSW Mw/Rv
	void decode_Mw_Rv(const uint8_t *buf)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg16>(buf); } else { decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg32>(buf); } }
	
	// TODO: throw an error if any of these return REG_INVALID
	// ModRM Memory Only
	void decode_Mo(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION128, indexToRegInvalid>(buf); }
	void decode_M(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToRegInvalid>(buf); }
	void decode_Ms(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToRegInvalid>(buf); }
	void decode_M108(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToRegInvalid>(buf); }  // Note this can be 108 or 98, but we just say "expression"
	void decode_M512(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToRegInvalid>(buf); }  // Note this can be 512 or 256, but we just say "expression"
	void decode_M28(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToRegInvalid>(buf); }  // Note this can be 28 or 14, but we just say "expression"
	void decode_Mw(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToRegInvalid>(buf); }
	void decode_Mp(const uint8_t *buf) 			{ decode_Ep(buf);}
	void decode_Mq(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegInvalid>(buf); }
	void decode_Md(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegInvalid>(buf); }
	void decode_Mb(const uint8_t *buf) 			{ decode_Ex<Operand::TYPE_EXPRESSION8, indexToRegInvalid>(buf); }
	void decode_Ma(const uint8_t *buf) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegInvalid>(buf); } else { decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegInvalid>(buf); } }
	void decode_Ep(const uint8_t *buf) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegInvalid>(buf); } else { decode_Ex<Operand::TYPE_EXPRESSION48, indexToRegInvalid>(buf); } }
	
	// FPU memory only
	void decode_WordInteger(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToRegInvalid>(buf); }
	void decode_SingleReal(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegInvalid>(buf); }
	void decode_ShortInteger(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegInvalid>(buf); }
	void decode_DoubleReal(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegInvalid>(buf); }			
	void decode_LongInteger(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegInvalid>(buf); }
	void decode_ExtendedReal(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION80, indexToRegInvalid>(buf); }
	void decode_PackedBCD(const uint8_t *buf) 	{ decode_Ex<Operand::TYPE_EXPRESSION80, indexToRegInvalid>(buf); }
	
	// ModRM selects a register only (mod must be 0x3)
	// TODO: throw an error if any of these return TYPE_INVALID
	void decode_Rv(const uint8_t *buf);
	void decode_Rw(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToReg16>(buf); }
	void decode_Rd(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToReg32>(buf); }
	void decode_Rq(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToReg64>(buf); }
	void decode_PRq(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToRegMMX>(buf); }
	void decode_VRo(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToRegXMMX>(buf); }
	void decode_VRq(const uint8_t *buf)			{ decode_Ex<Operand::TYPE_INVALID, indexToRegXMMX>(buf); }

	// ModRM Reg Field
	void decode_Gv(const uint8_t *buf);
	void decode_Gb(const uint8_t *buf) 			{ decode_Gx<indexToReg8>(buf); }
	void decode_Gw(const uint8_t *buf) 			{ decode_Gx<indexToReg16>(buf); }
	void decode_Gd(const uint8_t *buf) 			{ decode_Gx<indexToReg32>(buf); }
	void decode_Gz(const uint8_t *buf) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Gx<indexToReg16>(buf); } else { decode_Gx<indexToReg32>(buf); } }
	void decode_Vo(const uint8_t *buf) 			{ decode_Gx<indexToRegXMMX>(buf); }
	void decode_Vd(const uint8_t *buf) 			{ decode_Gx<indexToRegXMMX>(buf); }
	void decode_Vq(const uint8_t *buf) 			{ decode_Gx<indexToRegXMMX>(buf); }
	void decode_Pq(const uint8_t *buf)			{ decode_Gx<indexToRegMMX>(buf); }
	void decode_Pd(const uint8_t *buf)			{ decode_Gx<indexToRegMMX>(buf); }
	
	
	// Decode [C/D/T]Rx from ModRM reg
	void decode_Sw(const uint8_t *buf)			{ decode_Gx<indexToRegSeg>(buf); }
	void decode_Cd(const uint8_t *buf)			{ decode_Gx<indexToRegCR>(buf); }
	void decode_Dd(const uint8_t *buf)			{ decode_Gx<indexToRegDR>(buf); }
	void decode_Td(const uint8_t *buf)			{ decode_Gx<indexToRegTR>(buf); }
	
	// Immidiate
	void decode_Ib(const uint8_t *buf);
	void decode_Iw(const uint8_t *buf);
	void decode_Id(const uint8_t *buf);
	void decode_Iq(const uint8_t *buf);
	void decode_Iz(const uint8_t *buf)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Iw(buf); } else { decode_Id(buf); } }
	void decode_Iv(const uint8_t *buf);
	
	// EIP relative
	void decode_Jb(const uint8_t *buf);
	void decode_Jw(const uint8_t *buf);
	void decode_Jd(const uint8_t *buf);
	void decode_Jq(const uint8_t *buf);
	void decode_Jz(const uint8_t *buf)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Jw(buf); } else { decode_Jd(buf); } }
	
	// Direct offset
	void decode_Ob(const uint8_t *buf);
	void decode_Ow(const uint8_t *buf);
	void decode_Od(const uint8_t *buf);
	void decode_Ov(const uint8_t *buf);
	
	// Absolute address
	void decode_Ap(const uint8_t *buf);
	
	// Decode Specific Register
	void decode_rAX(const uint8_t *buf);
	void decode_rCX(const uint8_t *buf);
	void decode_rDX(const uint8_t *buf);
	void decode_rBX(const uint8_t *buf);
	void decode_rSP(const uint8_t *buf);
	void decode_rBP(const uint8_t *buf);
	void decode_rSI(const uint8_t *buf);
	void decode_rDI(const uint8_t *buf);
 	
private:
	// 2 operand modes
	template<int index>
	void decode_ST_STi(const uint8_t *buf)		{ decode<&Instruction::decode_Reg<Operand::REG_ST>, &Instruction::decode_STi<index> >(buf); }
	
	template<int index>
	void decode_STi_ST(const uint8_t *buf)		{ decode<&Instruction::decode_STi<index>, &Instruction::decode_Reg<Operand::REG_ST> >(buf); }

	void decode_Vo_Wd(const uint8_t *buf)			{ decode<&Instruction::decode_Vo, &Instruction::decode_Wd>(buf); }
	void decode_Ed_Vo(const uint8_t *buf)			{ decode<&Instruction::decode_Ed, &Instruction::decode_Vo>(buf); }
	void decode_Vd_Wo(const uint8_t *buf)			{ decode<&Instruction::decode_Vd, &Instruction::decode_Wo>(buf); }
	void decode_Qo_Wo(const uint8_t *buf)			{ decode<&Instruction::decode_Qo, &Instruction::decode_Wo>(buf); }
	void decode_Mq_Pq(const uint8_t *buf)			{ decode<&Instruction::decode_Mq, &Instruction::decode_Pq>(buf); }
	void decode_Gv_Mp(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_Mp>(buf); }
	void decode_Vo_Qq(const uint8_t *buf)			{ decode<&Instruction::decode_Vo, &Instruction::decode_Qq>(buf); }
	void decode_Qq_Wo(const uint8_t *buf)			{ decode<&Instruction::decode_Qq, &Instruction::decode_Wo>(buf); }
	void decode_Ev_Sw(const uint8_t *buf)			{ decode<&Instruction::decode_Ev, &Instruction::decode_Sw>(buf); }
	void decode_Sw_Ew(const uint8_t *buf)			{ decode<&Instruction::decode_Sw, &Instruction::decode_Ew>(buf); }
	void decode_Ev_Iz(const uint8_t *buf)			{ decode<&Instruction::decode_Ev, &Instruction::decode_Iz>(buf); }
	void decode_Rd_Cd(const uint8_t *buf)			{ decode<&Instruction::decode_Rd, &Instruction::decode_Cd>(buf); }
	void decode_Rd_Dd(const uint8_t *buf)			{ decode<&Instruction::decode_Rd, &Instruction::decode_Dd>(buf); }
	void decode_Rd_Td(const uint8_t *buf)			{ decode<&Instruction::decode_Rd, &Instruction::decode_Td>(buf); }
	void decode_Cd_Rd(const uint8_t *buf)		 	{ decode<&Instruction::decode_Cd, &Instruction::decode_Rd>(buf); }
	void decode_Dd_Rd(const uint8_t *buf)		 	{ decode<&Instruction::decode_Dd, &Instruction::decode_Rd>(buf); }
	void decode_Td_Rd(const uint8_t *buf)		 	{ decode<&Instruction::decode_Td, &Instruction::decode_Rd>(buf); }
	void decode_Gd_PRq(const uint8_t *buf)		{ decode<&Instruction::decode_Gd, &Instruction::decode_PRq>(buf); }
	void decode_Gd_VRo(const uint8_t *buf)		{ decode<&Instruction::decode_Gd, &Instruction::decode_VRo>(buf); }	
	void decode_AL_DX(const uint8_t *buf)			{ decode<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Reg<Operand::REG_DX> >(buf); }
	void decode_rAX_DX(const uint8_t *buf)		{ decode<&Instruction::decode_rAX, &Instruction::decode_Reg<Operand::REG_DX> >(buf); }
	void decode_DX_AL(const uint8_t *buf)			{ decode<&Instruction::decode_Reg<Operand::REG_DX>, &Instruction::decode_Reg<Operand::REG_AL> >(buf); }
	void decode_DX_rAX(const uint8_t *buf)		{ decode<&Instruction::decode_Reg<Operand::REG_DX>, &Instruction::decode_rAX >(buf); }
	void decode_Eb_CL(const uint8_t *buf) 		{ decode<&Instruction::decode_Eb, &Instruction::decode_Reg<Operand::REG_CL> >(buf); }
	void decode_Ev_CL(const uint8_t *buf) 		{ decode<&Instruction::decode_Ev, &Instruction::decode_Reg<Operand::REG_CL> >(buf); }
	void decode_AL_Ob(const uint8_t *buf)			{ decode<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Ob>(buf); }
	void decode_rAX_Ov(const uint8_t *buf)		{ decode<&Instruction::decode_rAX, &Instruction::decode_Ov>(buf); }
	void decode_Ob_AL(const uint8_t *buf)			{ decode<&Instruction::decode_Ob, &Instruction::decode_Reg<Operand::REG_AL> >(buf); }
	void decode_Ov_rAX(const uint8_t *buf)		{ decode<&Instruction::decode_Ov, &Instruction::decode_rAX >(buf); }
	void decode_AL_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Ib>(buf); }
	void decode_CL_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_CL>, &Instruction::decode_Ib>(buf); }
	void decode_DL_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_DL>, &Instruction::decode_Ib>(buf); }
	void decode_BL_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_BL>, &Instruction::decode_Ib>(buf); }
	void decode_AH_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_AH>, &Instruction::decode_Ib>(buf); }
	void decode_CH_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_CH>, &Instruction::decode_Ib>(buf); }
	void decode_DH_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_DH>, &Instruction::decode_Ib>(buf); }
	void decode_BH_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Reg<Operand::REG_BH>, &Instruction::decode_Ib>(buf); }
	void decode_rAX_Ib(const uint8_t *buf)		{ decode<&Instruction::decode_rAX, &Instruction::decode_Ib>(buf); }
	void decode_Ib_rAX(const uint8_t *buf)		{ decode<&Instruction::decode_Ib, &Instruction::decode_rAX >(buf); }
	void decode_Ib_AL(const uint8_t *buf)			{ decode<&Instruction::decode_Ib, &Instruction::decode_Reg<Operand::REG_AL> >(buf); }
	void decode_rAX_Iz(const uint8_t *buf)		{ decode<&Instruction::decode_rAX, &Instruction::decode_Iz>(buf); }
	void decode_rAX_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rAX, &Instruction::decode_Iv>(buf); }
	void decode_rCX_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rCX, &Instruction::decode_Iv>(buf); }
	void decode_rDX_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rDX, &Instruction::decode_Iv>(buf); }
	void decode_rBX_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rBX, &Instruction::decode_Iv>(buf); }
	void decode_rSP_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rSP, &Instruction::decode_Iv>(buf); }
	void decode_rBP_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rBP, &Instruction::decode_Iv>(buf); }
	void decode_rSI_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rSI, &Instruction::decode_Iv>(buf); }
	void decode_rDI_Iv(const uint8_t *buf)		{ decode<&Instruction::decode_rDI, &Instruction::decode_Iv>(buf); }
	void decode_rCX_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rCX, &Instruction::decode_rAX >(buf); }
	void decode_rDX_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rDX, &Instruction::decode_rAX >(buf); }
	void decode_rBX_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rBX, &Instruction::decode_rAX >(buf); }
	void decode_rSP_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rSP, &Instruction::decode_rAX >(buf); }
	void decode_rBP_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rBP, &Instruction::decode_rAX >(buf); }
	void decode_rSI_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rSI, &Instruction::decode_rAX >(buf); }
	void decode_rDI_rAX(const uint8_t *buf) 		{ decode<&Instruction::decode_rDI, &Instruction::decode_rAX >(buf); }
	void decode_Vo_Wo(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Wo>(buf); }
	void decode_Mo_Vo(const uint8_t *buf) 		{ decode<&Instruction::decode_Mo, &Instruction::decode_Vo>(buf); }
	void decode_Wo_Vo(const uint8_t *buf) 		{ decode<&Instruction::decode_Wo, &Instruction::decode_Vo>(buf); }
	void decode_Eb_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Eb, &Instruction::decode_Ib>(buf); }	
	void decode_Ev_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_Ev, &Instruction::decode_Ib>(buf); }	
	void decode_Eb_1(const uint8_t *buf)			{ decode<&Instruction::decode_Eb, &Instruction::decode_const_Ib<1> >(buf); }
	void decode_Ev_1(const uint8_t *buf)			{ decode<&Instruction::decode_Ev, &Instruction::decode_const_Id<1> >(buf); }
	void decode_Iw_Ib(const uint8_t *buf)			{ decode<&Instruction::decode_Iw, &Instruction::decode_Ib>(buf); }
	void decode_Gz_Mp(const uint8_t *buf)			{ decode<&Instruction::decode_Gz, &Instruction::decode_Mp>(buf); }
	void decode_Gv_M(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_M>(buf); }
	void decode_Gv_Ma(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_Ma>(buf); }
	void decode_Gb_Eb(const uint8_t *buf)			{ decode<&Instruction::decode_Gb, &Instruction::decode_Eb>(buf); }
	void decode_Gv_Eb(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_Eb>(buf); }
	void decode_Gv_Ev(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_Ev>(buf); }
	void decode_Eb_Gb(const uint8_t *buf)			{ decode<&Instruction::decode_Eb, &Instruction::decode_Gb>(buf); }
	void decode_Ew_Gw(const uint8_t *buf)			{ decode<&Instruction::decode_Ew, &Instruction::decode_Gw>(buf); }
	void decode_Ev_Gv(const uint8_t *buf)			{ decode<&Instruction::decode_Ev, &Instruction::decode_Gv>(buf); }
	void decode_Gv_Ew(const uint8_t *buf)			{ decode<&Instruction::decode_Gv, &Instruction::decode_Ew>(buf); }
	void decode_Pq_Ed(const uint8_t *buf) 		{ decode<&Instruction::decode_Pq, &Instruction::decode_Ed>(buf); }
	void decode_Pq_Qd(const uint8_t *buf) 		{ decode<&Instruction::decode_Pq, &Instruction::decode_Qd>(buf); }
	void decode_Pq_Qq(const uint8_t *buf) 		{ decode<&Instruction::decode_Pq, &Instruction::decode_Qq>(buf); }
	void decode_Qq_Pq(const uint8_t *buf) 		{ decode<&Instruction::decode_Qq, &Instruction::decode_Pq>(buf); }
	void decode_Vd_Wd(const uint8_t *buf) 		{ decode<&Instruction::decode_Vd, &Instruction::decode_Wd>(buf); }
	void decode_Vo_Wq(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Wq>(buf); }
	void decode_Vq_Mq(const uint8_t *buf) 		{ decode<&Instruction::decode_Vq, &Instruction::decode_Mq>(buf); }
	void decode_Mq_Vq(const uint8_t *buf) 		{ decode<&Instruction::decode_Mq, &Instruction::decode_Vq>(buf); }
	void decode_Ed_Pd(const uint8_t *buf) 		{ decode<&Instruction::decode_Ed, &Instruction::decode_Pd>(buf); }
	void decode_Md_Gd(const uint8_t *buf) 		{ decode<&Instruction::decode_Md, &Instruction::decode_Gd>(buf); }
	void decode_Pq_PRq(const uint8_t *buf) 		{ decode<&Instruction::decode_Pq, &Instruction::decode_PRq>(buf); }
	void decode_Wd_Vd(const uint8_t *buf) 		{ decode<&Instruction::decode_Wd, &Instruction::decode_Vd>(buf); }
	void decode_Vd_Ed(const uint8_t *buf) 		{ decode<&Instruction::decode_Vd, &Instruction::decode_Ed>(buf); }
	void decode_Gd_Wd(const uint8_t *buf) 		{ decode<&Instruction::decode_Gd, &Instruction::decode_Wd>(buf); }
	void decode_Md_Vd(const uint8_t *buf) 		{ decode<&Instruction::decode_Md, &Instruction::decode_Vd>(buf); }
	void decode_Vo_Mq(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Mq>(buf); }
	void decode_Vo_PRq(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_PRq>(buf); }
	void decode_Vq_Wq(const uint8_t *buf) 		{ decode<&Instruction::decode_Vq, &Instruction::decode_Wq>(buf); }
	void decode_Vo_Ed(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Ed>(buf); }
	void decode_Vo_Vo(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Vo>(buf); }
	void decode_Vo_VRo(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_VRo>(buf); }
	void decode_Wq_Vq(const uint8_t *buf) 		{ decode<&Instruction::decode_Wq, &Instruction::decode_Vq>(buf); }
	void decode_Gd_Wq(const uint8_t *buf) 		{ decode<&Instruction::decode_Gd, &Instruction::decode_Wq>(buf); }
	void decode_Vq_Ed(const uint8_t *buf) 		{ decode<&Instruction::decode_Vq, &Instruction::decode_Ed>(buf); }
	void decode_Vo_Mo(const uint8_t *buf) 		{ decode<&Instruction::decode_Vo, &Instruction::decode_Mo>(buf); }
	void decode_Pq_VRq(const uint8_t *buf) 		{ decode<&Instruction::decode_Pq, &Instruction::decode_VRq>(buf); }	
	void decode_Ed_Gd(const uint8_t *buf) 		{ decode<&Instruction::decode_Ed, &Instruction::decode_Gd>(buf); }
	void decode_Gd_Ed(const uint8_t *buf) 		{ decode<&Instruction::decode_Gd, &Instruction::decode_Ed>(buf); }
	void decode_PRq_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_PRq, &Instruction::decode_Ib>(buf); }
	void decode_VRo_Ib(const uint8_t *buf) 		{ decode<&Instruction::decode_VRo, &Instruction::decode_Ib>(buf); }
	
private:
	// 3 operand modes
	void decode_Pq_Ew_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Pq, &Instruction::decode_Ew, &Instruction::decode_Ib>(buf); }
	void decode_Gv_Ev_Iz(const uint8_t *buf)	{ decode<&Instruction::decode_Gv, &Instruction::decode_Ev, &Instruction::decode_Iz>(buf); }
	void decode_Gv_Ev_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Gv, &Instruction::decode_Ev, &Instruction::decode_Ib>(buf); }
	void decode_Ev_Gv_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Ev, &Instruction::decode_Gv, &Instruction::decode_Ib>(buf); }
	void decode_Vo_Wo_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Vo, &Instruction::decode_Wo, &Instruction::decode_Ib>(buf); }
	void decode_Gd_PRq_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Gd, &Instruction::decode_PRq, &Instruction::decode_Ib>(buf); }
	void decode_Pq_Qq_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Pq, &Instruction::decode_Qq, &Instruction::decode_Ib>(buf); }
	void decode_Vd_Wd_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Vd, &Instruction::decode_Wd, &Instruction::decode_Ib>(buf); }
	void decode_Vo_Mw_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Vo, &Instruction::decode_Mw, &Instruction::decode_Ib>(buf); }
	void decode_Gd_VRo_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Gd, &Instruction::decode_VRo, &Instruction::decode_Ib>(buf); }
	void decode_Vq_Wq_Ib(const uint8_t *buf)	{ decode<&Instruction::decode_Vq, &Instruction::decode_Wq, &Instruction::decode_Ib>(buf); }
	
	template<Operand::Register REG>
	void decode_Ev_Gv_Reg(const uint8_t *buf)	{ decode<&Instruction::decode_Ev, &Instruction::decode_Gv, &Instruction::decode_Reg<REG> >(buf); }

private:
	static Operand::Register indexToRegInvalid(uint8_t)				{ return Operand::REG_INVALID; }
	static Operand::Register indexToReg8(uint8_t index)				{ return static_cast<Operand::Register>(Operand::REG_AL + index); }
	static Operand::Register indexToReg16(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_AX + index); }
	static Operand::Register indexToReg32(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_EAX + index); }
	static Operand::Register indexToReg64(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_RAX + index); }
	static Operand::Register indexToRegSeg(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_ES + index); }
	static Operand::Register indexToRegMMX(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_MM0 + index); }
	static Operand::Register indexToRegXMMX(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_XMM0 + index); }
	static Operand::Register indexToRegFPU(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_ST0 + index); }
	static Operand::Register indexToRegCR(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_CR0 + index); }
	static Operand::Register indexToRegDR(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_DR0 + index); }
	static Operand::Register indexToRegTR(uint8_t index)			{ return static_cast<Operand::Register>(Operand::REG_TR0 + index); }
	
public:
	std::string format() const;
	std::string format(bool upper) const;
	std::string mnemonic() const					{ return m_Mnemonic; }
	uint_t operandCount() const						{ return m_OperandCount; }
	uint_t prefixSize() const						{ return m_PrefixSize; }
	uint_t size() const								{ return m_PrefixSize + m_RexSize + m_OpcodeSize + m_ModRMSize + m_SIBSize + m_DispSize + m_ImmidiateSize; }
	uint32_t prefix() const							{ return m_Prefix; }
	uint32_t rva16() const							{ return m_IP; }
	uint32_t rva32() const							{ return m_EIP; }
	uint64_t rva64() const							{ return m_RIP; }
	bool valid() const								{ return m_Type != OP_INVALID; }
	Type type() const								{ return m_Type; }
	const uint8_t *buffer() const					{ return m_Buffer; }
	const Operand &operand(std::size_t index) const	{ return m_Operands[index]; }

private:
	std::string formatPrefix() const;
	int operandSize() const;
	
private:
	struct OpcodeEntry {
		const char 		*mnemonic;
		DecoderFunction	decoder;
		Type			type;
	};
	
private:
	static const OpcodeEntry m_OpcodesX87Hi[0x200];
	static const OpcodeEntry m_Opcodes[0x100];
	static const OpcodeEntry m_Opcodes2Byte_NA[0x100];
	static const OpcodeEntry m_Opcodes2Byte_66[0x100];
	static const OpcodeEntry m_Opcodes2Byte_F2[0x100];
	static const OpcodeEntry m_Opcodes2Byte_F3[0x100];
	static const OpcodeEntry m_Opcodes3Byte_38_NA[0x100];
	static const OpcodeEntry m_Opcodes3Byte_38_66[0x100];
	static const OpcodeEntry m_Opcodes3Byte_3A_NA[0x100];
	static const OpcodeEntry m_Opcodes3Byte_3A_66[0x100];
	static const OpcodeEntry m_OpcodesX87Lo[64];
	
private:
	static const OpcodeEntry m_OpcodesGroup1[32];
	static const OpcodeEntry m_OpcodesGroup2[16];
	static const OpcodeEntry m_OpcodesGroup2D[32];
	static const OpcodeEntry m_OpcodesGroup3[16];
	static const OpcodeEntry m_OpcodesGroup4[8];
	static const OpcodeEntry m_OpcodesGroup5[8];
	static const OpcodeEntry m_OpcodesGroup6[8];
	static const OpcodeEntry m_OpcodesGroup7[8];
	static const OpcodeEntry m_OpcodesGroup7A[64];
	static const OpcodeEntry m_OpcodesGroup8[8];
	static const OpcodeEntry m_OpcodesGroup9[8];
	static const OpcodeEntry m_OpcodesGroup9_66[8];
	static const OpcodeEntry m_OpcodesGroup9_F3[8];
	static const OpcodeEntry m_OpcodesGroup10[8];
	static const OpcodeEntry m_OpcodesGroup11[8];
	static const OpcodeEntry m_OpcodesGroup12[16];
	static const OpcodeEntry m_OpcodesGroup13[8];
	static const OpcodeEntry m_OpcodesGroup13_66[8];
	static const OpcodeEntry m_OpcodesGroup14[8];
	static const OpcodeEntry m_OpcodesGroup14_66[8];
	static const OpcodeEntry m_OpcodesGroup15[8];
	static const OpcodeEntry m_OpcodesGroup15_66[8];
	static const OpcodeEntry m_OpcodesGroup16_Reg[8];
	static const OpcodeEntry m_OpcodesGroup16_Mem[8];
	static const OpcodeEntry m_OpcodesGroup17[64];

private:	
	Operand	m_Operands[MAX_OPERANDS];
	
	union {
		uint16_t m_IP;
		uint32_t m_EIP;
		uint64_t m_RIP;
	};
	
	const uint8_t *const m_Buffer;
	std::size_t m_BufferSize;
	const OpcodeEntry *m_Opcode;
	const char *m_Mnemonic;
	Type m_Type;
	Mode m_Mode;
	
	uint32_t m_Prefix;
	uint32_t m_MandatoryPrefix;
	uint8_t m_OperandCount;
	uint8_t m_ModRMSize;
	uint8_t m_SIBSize;
	uint8_t m_DispSize;
	uint8_t m_PrefixSize;
	uint8_t m_ImmidiateSize;
	uint8_t m_OpcodeSize;
	uint8_t m_RexByte;
	uint8_t m_RexSize;
};

#endif
