/*
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"
#include "ModRM.h"
#include "SIB.h"

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) {} };
#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;
	
	static const int MAX_SIZE = 20;
	
public:
	Instruction(const uint8_t *buf, std::size_t size, uint64_t rva, const std::nothrow_t&) throw();
	Instruction(const uint8_t *buf, std::size_t size, uint64_t rva);

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 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 *, std::size_t);
	
private:
	// convinience binders,
	template<DecoderFunction F1, DecoderFunction F2, DecoderFunction F3, DecoderFunction F4>
	void decode4(const uint8_t *buf, std::size_t size) {
		(this->*F1)(buf, size);
		(this->*F2)(buf, size);
		(this->*F3)(buf, size);
		(this->*F4)(buf, size);
	}
	
	template<DecoderFunction F1, DecoderFunction F2, DecoderFunction F3>
	void decode3(const uint8_t *buf, std::size_t size) {
		(this->*F1)(buf, size);
		(this->*F2)(buf, size);
		(this->*F3)(buf, size);
	}
	
	template<DecoderFunction F1, DecoderFunction F2>
	void decode2(const uint8_t *buf, std::size_t size) {
		(this->*F1)(buf, size);
		(this->*F2)(buf, size);
	}
	
	template<DecoderFunction F1>
	void decode1(const uint8_t *buf, std::size_t size) {
		(this->*F1)(buf, size);
	}
	

private:

	void decode0(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);
		// does nothing
	}
	
private:
	// special cased names
	void decode_cwde_cbw(const uint8_t *buf, std::size_t size);
	void decode_cdq_cwd(const uint8_t *buf, std::size_t size);
	void decode_pushfd_pushfw(const uint8_t *buf, std::size_t size);
	void decode_popfd_popfw(const uint8_t *buf, std::size_t size);
	void decode_movsd_movsw(const uint8_t *buf, std::size_t size);
	void decode_cmpsd_cmpsw(const uint8_t *buf, std::size_t size);
	void decode_stosd_stosw(const uint8_t *buf, std::size_t size);
	void decode_lodsd_lodsw(const uint8_t *buf, std::size_t size);
	void decode_scasd_scasw(const uint8_t *buf, std::size_t size);
	void decode_iret_iretw(const uint8_t *buf, std::size_t size);
	void decode_nop_pause(const uint8_t *buf, std::size_t size);

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

private:
	
	template<Operand::Type TYPE>
	void decode_Offset(const uint8_t *buf, std::size_t size) {
		Operand &operand(nextOperand());
		
		operand.expression.index				= Operand::REG_NONE;
		operand.expression.scale				= 1;
		operand.expression.base					= Operand::REG_NONE;
		operand.expression.s_disp32				= getDisplacement<int32_t>(buf, size);
		operand.m_Type							= TYPE;
		operand.expression.displacement_type	= Operand::DISP_S32;
	}
	
	template<Operand::Register REG>
	void decode_Reg(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);
		
		Operand &operand(nextOperand());

		operand.reg 	= REG;
		operand.m_Type	= Operand::TYPE_REGISTER;
	}
	
	template<int32_t IMM>
	void decode_const_Id(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);

		Operand &operand(nextOperand());

		operand.sdword	= IMM;
		operand.m_Type	= Operand::TYPE_IMMEDIATE32;
		m_ImmidiateSize	+= sizeof(int32_t);
	}
	
	template<int32_t IMM>
	void decode_const_Iw(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);

		Operand &operand(nextOperand());

		operand.word	= IMM;
		operand.m_Type	= Operand::TYPE_IMMEDIATE16;
		m_ImmidiateSize	+= sizeof(int16_t);
	}
	
	template<int8_t IMM>
	void decode_const_Ib(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);

		Operand &operand(nextOperand());

		operand.sbyte	= IMM;
		operand.m_Type	= Operand::TYPE_IMMEDIATE8;
		m_ImmidiateSize	+= sizeof(int8_t);
	}
	
	template<typename T>
	T getImmidiate(const uint8_t *buf, std::size_t size) {

		BOUNDS_CHECK(Instruction::size() + sizeof(T), size);

		const T ret = *reinterpret_cast<const T *>(&buf[m_OpcodeSize + m_ModRMSize + m_SIBSize + m_DispSize + m_ImmidiateSize]);
		m_ImmidiateSize += sizeof(T);
		return ret;
	}
	
	template<typename T>
	T getDisplacement(const uint8_t *buf, std::size_t size) {		
		BOUNDS_CHECK(Instruction::size() + sizeof(T), size);
		
		const T ret = *reinterpret_cast<const T *>(&buf[m_OpcodeSize + m_ModRMSize + m_SIBSize + m_DispSize]);
		m_DispSize = sizeof(T);
		return ret;
	}
	
	template<int index>
	void decode_STi(const uint8_t *buf, std::size_t size) {
		UNUSED(buf);
		UNUSED(size);
	
		Operand &operand(nextOperand());
		operand.reg		= indexToRegFPU(index);
		operand.m_Type	= Operand::TYPE_REGISTER;
	}
	
	
	template<Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_Gx(const uint8_t *buf, std::size_t size) {
		
		// we got enough room for the ModRM byte?
		if(m_ModRMSize == 0) {
			BOUNDS_CHECK(Instruction::size() + 1, size);
		}
		
		ModRM rm(buf[m_OpcodeSize]);
		m_ModRMSize = 1;
		
		Operand &operand(nextOperand());
		operand.reg		= (*REG_DECODE)(rm.reg());
		operand.m_Type	= Operand::TYPE_REGISTER;
	}
	
	
	
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_0_16(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
	
		switch(rm.rm()) {
		case 0x00:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_BX;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x01:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_BX;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x02:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_BP;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x03:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_BP;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x04:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_NONE;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x05:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_NONE;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
		case 0x06:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_NONE;
			operand.expression.s_disp16			= getDisplacement<int16_t>(buf, size);
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_S16;
			break;
		case 0x07:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.scale			= 1;
			operand.expression.base				= Operand::REG_BX;
			operand.m_Type						= TYPE;
			operand.expression.displacement_type= Operand::DISP_NONE;
			break;
			
		}
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_1_16(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
	
		operand.m_Type				= TYPE;
		operand.expression.scale	= 1;
		switch(rm.rm()) {
		case 0x00:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_BX;
			break;
		case 0x01:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_BX;
			break;
		case 0x02:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x03:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x04:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_NONE;
			break;
		case 0x05:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_NONE;
			break;
		case 0x06:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x07:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.base				= Operand::REG_BX;
			break;
		}
		operand.expression.s_disp8				= getDisplacement<int8_t>(buf, size);
		operand.expression.displacement_type	= Operand::DISP_S8;
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_2_16(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		operand.m_Type				= TYPE;
		operand.expression.scale	= 1;
		switch(rm.rm()) {
		case 0x00:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_BX;
			break;
		case 0x01:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_BX;
			break;
		case 0x02:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x03:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x04:
			operand.expression.index			= Operand::REG_SI;
			operand.expression.base				= Operand::REG_NONE;
			break;
		case 0x05:
			operand.expression.index			= Operand::REG_DI;
			operand.expression.base				= Operand::REG_NONE;
			break;
		case 0x06:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.base				= Operand::REG_BP;
			break;
		case 0x07:
			operand.expression.index			= Operand::REG_NONE;
			operand.expression.base				= Operand::REG_BX;
			break;
		}
		operand.expression.s_disp16				= getDisplacement<int16_t>(buf, size);
		operand.expression.displacement_type	= Operand::DISP_S16;
	}
	
	
	
	
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_0(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		
		if(rm.rm() == 0x04) {
			// we got enough room for the SIB byte?
			if(m_SIBSize == 0) {
				BOUNDS_CHECK(Instruction::size() + 1, size);
			}
			
			m_SIBSize = 1;
			SIB sib(buf[m_OpcodeSize + m_ModRMSize]);

			if(sib.index() != 0x04) {
				operand.expression.index			= indexToReg32(sib.index());
				operand.expression.scale			= 1 << sib.scale();
				operand.expression.base				= indexToReg32(sib.base());
				operand.m_Type						= TYPE;
				operand.expression.displacement_type= Operand::DISP_NONE;
			} else {
				operand.expression.index			= Operand::REG_NONE;
				operand.expression.scale			= 1;
				operand.expression.base				= indexToReg32(sib.base());
				operand.m_Type						= TYPE;
				operand.expression.displacement_type= Operand::DISP_NONE;
			}
		} else if(rm.rm() == 0x05) {
			operand.expression.index				= Operand::REG_NONE;
			operand.expression.scale				= 1;
			operand.expression.base					= Operand::REG_NONE;
			operand.expression.s_disp32				= getDisplacement<int32_t>(buf, size);
			operand.m_Type							= TYPE;
			operand.expression.displacement_type	= Operand::DISP_S32;
		} else {
			operand.expression.index				= Operand::REG_NONE;
			operand.expression.scale				= 1;
			operand.expression.base					= indexToReg32(rm.rm());
			operand.expression.s_disp8				= 0;
			operand.m_Type							= TYPE;
			operand.expression.displacement_type	= Operand::DISP_NONE;
		}
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_1(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		if(rm.rm() == 0x04) {
		
			// we got enough room for the SIB byte?
			if(m_SIBSize == 0) {
				BOUNDS_CHECK(Instruction::size() + 1, size);
			}
		
			m_SIBSize = 1;
			SIB sib(buf[m_OpcodeSize + m_ModRMSize]);
			
			if(sib.index() != 0x04) {
				operand.expression.index			= indexToReg32(sib.index());
				operand.expression.scale			= 1 << sib.scale();
				operand.expression.base				= indexToReg32(sib.base());
				operand.expression.s_disp8			= getDisplacement<int8_t>(buf, size);
				operand.m_Type						= TYPE;
				operand.expression.displacement_type= Operand::DISP_S8;	
			} else {
				operand.expression.index			= indexToReg32(sib.index());
				operand.expression.scale			= 1 << sib.scale();
				operand.expression.base				= Operand::REG_NONE;
				operand.expression.s_disp8			= getDisplacement<int8_t>(buf, size);
				operand.m_Type						= TYPE;
				operand.expression.displacement_type= Operand::DISP_S8;			
			}
		} else {
			operand.expression.index				= Operand::REG_NONE;
			operand.expression.scale				= 1;
			operand.expression.base					= indexToReg32(rm.rm());
			operand.expression.s_disp8				= getDisplacement<int8_t>(buf, size);
			operand.m_Type							= TYPE;
			operand.expression.displacement_type	= Operand::DISP_S8;
		}
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_2(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		if(rm.rm() == 0x04) {
		
		
			// we got enough room for the SIB byte?
			if(m_SIBSize == 0) {
				BOUNDS_CHECK(Instruction::size() + 1, size);
			}
		
			m_SIBSize = 1;
			SIB sib(buf[m_OpcodeSize + m_ModRMSize]);
			
			if(sib.index() != 0x04) {
				operand.expression.index				= indexToReg32(sib.index());
				operand.expression.scale				= 1 << sib.scale();
				operand.expression.base					= indexToReg32(sib.base());
				operand.expression.s_disp32				= getDisplacement<int32_t>(buf, size);
				operand.m_Type							= TYPE;
				operand.expression.displacement_type	= Operand::DISP_S32;
			} else {
				operand.expression.index				= indexToReg32(sib.index());
				operand.expression.scale				= 1 << sib.scale();
				operand.expression.base					= Operand::REG_NONE;
				operand.expression.s_disp32				= getDisplacement<int32_t>(buf, size);
				operand.m_Type							= TYPE;
				operand.expression.displacement_type	= Operand::DISP_S32;		
			}


		} else {
			operand.expression.index				= Operand::REG_NONE;
			operand.expression.scale				= 1;
			operand.expression.base					= indexToReg32(rm.rm());
			operand.expression.s_disp32				= getDisplacement<int32_t>(buf, size);
			operand.m_Type							= TYPE;
			operand.expression.displacement_type	= Operand::DISP_S32;
		}
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_3(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		UNUSED(buf);
		UNUSED(size);
		
		operand.reg		= (*REG_DECODE)(rm.rm());
		operand.m_Type	= Operand::TYPE_REGISTER;
	}
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_ModRM_Invalid(const uint8_t *buf, std::size_t size, const ModRM &rm, Operand &operand) {
		UNUSED(rm);
		UNUSED(operand);
		UNUSED(buf);
		UNUSED(size);
		throw invalid_operand(Instruction::size());
	}
	
	
	template<Operand::Type TYPE, Operand::Register (*REG_DECODE)(uint8_t)>
	void decode_Ex(const uint8_t *buf, std::size_t size) {

		// we got enough room for the ModRM byte?
		if(m_ModRMSize == 0) {
			BOUNDS_CHECK(Instruction::size() + 1, size);
		}

		ModRM rm(buf[m_OpcodeSize]);
		m_ModRMSize = 1;

		Operand &operand(nextOperand());

		if(m_Prefix & PREFIX_ADDRESS) {			
			switch(rm.mod()) {
			case 0x00:
				decode_ModRM_0_16<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x01:
				decode_ModRM_1_16<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x02:
				decode_ModRM_2_16<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x03:
				// same as in 32-bit mode!
				decode_ModRM_3<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			}
		} else {
			switch(rm.mod()) {
			case 0x00:
				decode_ModRM_0<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x01:
				decode_ModRM_1<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x02:
				decode_ModRM_2<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			case 0x03:
				decode_ModRM_3<TYPE, REG_DECODE>(buf, size, rm, operand);
				break;
			}
		}
	}
	
private:

	// ModRM Reg or Memory 
	void decode_Eb(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION8, indexToReg8>(buf, size); }
	void decode_Ew(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg16>(buf, size); }
	void decode_Ed(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); }
	void decode_Ev(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg16>(buf, size); } else { decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); } }
	void decode_Ep(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); } else { decode_Ex<Operand::TYPE_EXPRESSION48, indexToReg32>(buf, size); } }
	void decode_Wd(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegXMMX>(buf, size); }	
	void decode_Wq(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegXMMX>(buf, size); }
	void decode_Wo(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION128, indexToRegXMMX>(buf, size); }	
	void decode_Qd(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegMMX>(buf, size); }
	void decode_Qq(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegMMX>(buf, size); }
	void decode_Qo(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION128, indexToRegMMX>(buf, size); }
	
	// special case for SMSW Mw/Rv
	void decode_Mw_Rv(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg16>(buf, size); } else { decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg32>(buf, size); } }
	
	
	// ModRM Memory Only
	// TODO: enforce memory only
	void decode_M(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }
	void decode_Mo(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }
	void decode_Ms(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }
	void decode_M108(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }	// Note this can be 108 or 98, but we just say "expression"
	void decode_M512(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }	// Note this can be 512 or 256, but we just say "expression"
	void decode_M28(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION, indexToReg32>(buf, size); }	// Note this can be 28 or 14, but we just say "expression"
	void decode_Mw(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToReg32>(buf, size); }
	void decode_Mp(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); } else { decode_Ex<Operand::TYPE_EXPRESSION48, indexToReg32>(buf, size); } }
	void decode_Mq(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToReg32>(buf, size); }
	void decode_Md(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); }
	void decode_Mb(const uint8_t *buf, std::size_t size) 			{ decode_Ex<Operand::TYPE_EXPRESSION8, indexToReg32>(buf, size); }
	void decode_Ma(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Ex<Operand::TYPE_EXPRESSION32, indexToReg32>(buf, size); } else { decode_Ex<Operand::TYPE_EXPRESSION64, indexToReg32>(buf, size); } }

	
	// FPU memory only
	// TODO: enforce memory only
	void decode_WordInteger(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION16, indexToRegFPU>(buf, size); }
	void decode_SingleReal(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegFPU>(buf, size); }
	void decode_ShortInteger(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION32, indexToRegFPU>(buf, size); }
	void decode_DoubleReal(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegFPU>(buf, size); }			
	void decode_LongInteger(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION64, indexToRegFPU>(buf, size); }
	void decode_ExtendedReal(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION80, indexToRegFPU>(buf, size); }
	void decode_PackedBCD(const uint8_t *buf, std::size_t size) 	{ decode_Ex<Operand::TYPE_EXPRESSION80, indexToRegFPU>(buf, size); }
	
	// ModRM selects a register only (mod must be 0x3)
	// TODO: enforce register only
	// TODO: correct?, should this not be an somehow a 32-bit register? ?
	void decode_Vd(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToRegXMMX>(buf, size); }
	void decode_Sw(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegSeg>(buf, size); }
	void decode_Rw(const uint8_t *buf, std::size_t size)			{ decode_Ew(buf, size); }
	void decode_Rd(const uint8_t *buf, std::size_t size)			{ decode_Ed(buf, size); }
	void decode_Rv(const uint8_t *buf, std::size_t size)			{ decode_Ev(buf, size); }
	void decode_PRq(const uint8_t *buf, std::size_t size)			{ decode_Wq(buf, size); }
	void decode_VRo(const uint8_t *buf, std::size_t size)			{ decode_Wo(buf, size); }
	void decode_VRq(const uint8_t *buf, std::size_t size)			{ decode_Wq(buf, size); }

	
	// ModRM Reg Field
	void decode_Gb(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToReg8>(buf, size); }
	void decode_Gw(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToReg16>(buf, size); }
	void decode_Gd(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToReg32>(buf, size); }
	void decode_Gv(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Gx<indexToReg16>(buf, size); } else { decode_Gx<indexToReg32>(buf, size); } }
	void decode_Gz(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Gx<indexToReg16>(buf, size); } else { decode_Gx<indexToReg32>(buf, size); } }
	void decode_Vo(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToRegXMMX>(buf, size); }
	void decode_Vq(const uint8_t *buf, std::size_t size) 			{ decode_Gx<indexToRegXMMX>(buf, size); }
	void decode_Pq(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegMMX>(buf, size); }
	void decode_Pd(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegMMX>(buf, size); }
	

	
	// Decode [C/D/T]Rx from ModRM reg
	void decode_Cd(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegCR>(buf, size); }
	void decode_Dd(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegDR>(buf, size); }
	void decode_Td(const uint8_t *buf, std::size_t size)			{ decode_Gx<indexToRegTR>(buf, size); }

	// Immidiate
	void decode_Ib(const uint8_t *buf, std::size_t size);
	void decode_Iw(const uint8_t *buf, std::size_t size);
	void decode_Id(const uint8_t *buf, std::size_t size);
	void decode_Iq(const uint8_t *buf, std::size_t size);
	void decode_Iz(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Iw(buf, size); } else { decode_Id(buf, size); } }
	void decode_Iv(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Iw(buf, size); } else { decode_Id(buf, size); } }
	
	// EIP relative
	void decode_Jb(const uint8_t *buf, std::size_t size);
	void decode_Jw(const uint8_t *buf, std::size_t size);
	void decode_Jd(const uint8_t *buf, std::size_t size);
	void decode_Jz(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Jw(buf, size); } else { decode_Jd(buf, size); } }
	
	// Direct offset
	void decode_Ob(const uint8_t *buf, std::size_t size) 			{ decode_Offset<Operand::TYPE_EXPRESSION8>(buf, size); }
	void decode_Ov(const uint8_t *buf, std::size_t size) 			{ if(m_Prefix & PREFIX_OPERAND) { decode_Offset<Operand::TYPE_EXPRESSION16>(buf, size); } else { decode_Offset<Operand::TYPE_EXPRESSION32>(buf, size); } }
	
	// Absolute address
	void decode_Ap(const uint8_t *buf, std::size_t size);
	
	// Decode Specific Register
	void decode_eAX(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_AX>(buf, size); } else { decode_Reg<Operand::REG_EAX>(buf, size); } }
	void decode_eCX(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_CX>(buf, size); } else { decode_Reg<Operand::REG_ECX>(buf, size); } }
	void decode_eDX(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_DX>(buf, size); } else { decode_Reg<Operand::REG_EDX>(buf, size); } }
	void decode_eBX(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_BX>(buf, size); } else { decode_Reg<Operand::REG_EBX>(buf, size); } }
	void decode_eSP(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_SP>(buf, size); } else { decode_Reg<Operand::REG_ESP>(buf, size); } }
	void decode_eBP(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_BP>(buf, size); } else { decode_Reg<Operand::REG_EBP>(buf, size); } }
	void decode_eSI(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_SI>(buf, size); } else { decode_Reg<Operand::REG_ESI>(buf, size); } }
	void decode_eDI(const uint8_t *buf, std::size_t size)			{ if(m_Prefix & PREFIX_OPERAND) { decode_Reg<Operand::REG_DI>(buf, size); } else { decode_Reg<Operand::REG_EDI>(buf, size); } }
 	
private:

	// 2 operand modes
	template<int index>
	void decode_ST_STi(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Reg<Operand::REG_ST>, &Instruction::decode_STi<index> >(buf, size); }
	template<int index>
	void decode_STi_ST(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_STi<index>, &Instruction::decode_Reg<Operand::REG_ST> >(buf, size); }

	void decode_Vo_Wd(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Vo, &Instruction::decode_Wd>(buf, size); }
	void decode_Ed_Vo(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ed, &Instruction::decode_Vo>(buf, size); }
	void decode_Vd_Wo(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Vd, &Instruction::decode_Wo>(buf, size); }
	void decode_Qo_Wo(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Qo, &Instruction::decode_Wo>(buf, size); }
	void decode_Mq_Pq(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Mq, &Instruction::decode_Pq>(buf, size); }
	void decode_Gv_Mp(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_Mp>(buf, size); }
	void decode_Vo_Qq(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Vo, &Instruction::decode_Qq>(buf, size); }	
	void decode_Qq_Wo(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Qq, &Instruction::decode_Wo>(buf, size); }	
	void decode_Ev_Sw(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ev, &Instruction::decode_Sw>(buf, size); }	
	void decode_Sw_Ew(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Sw, &Instruction::decode_Ew>(buf, size); }	
	void decode_Ev_Iz(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ev, &Instruction::decode_Iz>(buf, size); }	
	void decode_Rd_Cd(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Rd, &Instruction::decode_Cd>(buf, size); }
	void decode_Rd_Dd(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Rd, &Instruction::decode_Dd>(buf, size); }
	void decode_Rd_Td(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Rd, &Instruction::decode_Td>(buf, size); }
	void decode_Cd_Rd(const uint8_t *buf, std::size_t size)		 	{ decode2<&Instruction::decode_Cd, &Instruction::decode_Rd>(buf, size); }
	void decode_Dd_Rd(const uint8_t *buf, std::size_t size)		 	{ decode2<&Instruction::decode_Dd, &Instruction::decode_Rd>(buf, size); }
	void decode_Td_Rd(const uint8_t *buf, std::size_t size)		 	{ decode2<&Instruction::decode_Td, &Instruction::decode_Rd>(buf, size); }
	void decode_Gd_PRq(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Gd, &Instruction::decode_PRq>(buf, size); }	
	void decode_Gd_VRo(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Gd, &Instruction::decode_VRo>(buf, size); }	
	void decode_AL_DX(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Reg<Operand::REG_DX> >(buf, size); }
	void decode_eAX_DX(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eAX, &Instruction::decode_Reg<Operand::REG_DX> >(buf, size); }
	void decode_DX_AL(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Reg<Operand::REG_DX>, &Instruction::decode_Reg<Operand::REG_AL> >(buf, size); }
	void decode_DX_eAX(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Reg<Operand::REG_DX>, &Instruction::decode_eAX >(buf, size); }
	void decode_Eb_CL(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Eb, &Instruction::decode_Reg<Operand::REG_CL> >(buf, size); }
	void decode_Ev_CL(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Ev, &Instruction::decode_Reg<Operand::REG_CL> >(buf, size); }
	void decode_AL_Ob(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Ob>(buf, size); }
	void decode_eAX_Ov(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eAX, &Instruction::decode_Ov>(buf, size); }
	void decode_Ob_AL(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ob, &Instruction::decode_Reg<Operand::REG_AL> >(buf, size); }
	void decode_Ov_eAX(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Ov, &Instruction::decode_eAX >(buf, size); }
	void decode_AL_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_AL>, &Instruction::decode_Ib>(buf, size); }
	void decode_CL_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_CL>, &Instruction::decode_Ib>(buf, size); }
	void decode_DL_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_DL>, &Instruction::decode_Ib>(buf, size); }
	void decode_BL_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_BL>, &Instruction::decode_Ib>(buf, size); }
	void decode_AH_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_AH>, &Instruction::decode_Ib>(buf, size); }
	void decode_CH_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_CH>, &Instruction::decode_Ib>(buf, size); }
	void decode_DH_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_DH>, &Instruction::decode_Ib>(buf, size); }
	void decode_BH_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Reg<Operand::REG_BH>, &Instruction::decode_Ib>(buf, size); }
	void decode_eAX_Ib(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eAX, &Instruction::decode_Ib>(buf, size); }
	void decode_Ib_eAX(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_Ib, &Instruction::decode_eAX >(buf, size); }
	void decode_Ib_AL(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ib, &Instruction::decode_Reg<Operand::REG_AL> >(buf, size); }
	void decode_eAX_Iz(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eAX, &Instruction::decode_Iz>(buf, size); }
	void decode_eAX_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eAX, &Instruction::decode_Iv>(buf, size); }
	void decode_eCX_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eCX, &Instruction::decode_Iv>(buf, size); }
	void decode_eDX_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eDX, &Instruction::decode_Iv>(buf, size); }
	void decode_eBX_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eBX, &Instruction::decode_Iv>(buf, size); }
	void decode_eSP_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eSP, &Instruction::decode_Iv>(buf, size); }
	void decode_eBP_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eBP, &Instruction::decode_Iv>(buf, size); }
	void decode_eSI_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eSI, &Instruction::decode_Iv>(buf, size); }
	void decode_eDI_Iv(const uint8_t *buf, std::size_t size)		{ decode2<&Instruction::decode_eDI, &Instruction::decode_Iv>(buf, size); }
	void decode_eCX_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eCX, &Instruction::decode_eAX >(buf, size); }
	void decode_eDX_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eDX, &Instruction::decode_eAX >(buf, size); }
	void decode_eBX_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eBX, &Instruction::decode_eAX >(buf, size); }
	void decode_eSP_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eSP, &Instruction::decode_eAX >(buf, size); }
	void decode_eBP_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eBP, &Instruction::decode_eAX >(buf, size); }
	void decode_eSI_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eSI, &Instruction::decode_eAX >(buf, size); }
	void decode_eDI_eAX(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_eDI, &Instruction::decode_eAX >(buf, size); }
	void decode_Vo_Wo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Wo>(buf, size); }
	void decode_Mo_Vo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Mo, &Instruction::decode_Vo>(buf, size); }
	void decode_Wo_Vo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Wo, &Instruction::decode_Vo>(buf, size); }
	void decode_Eb_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Eb, &Instruction::decode_Ib>(buf, size); }	
	void decode_Ev_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Ev, &Instruction::decode_Ib>(buf, size); }	
	void decode_Eb_1(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Eb, &Instruction::decode_const_Ib<1> >(buf, size); }
	void decode_Ev_1(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ev, &Instruction::decode_const_Id<1> >(buf, size); }
	void decode_Iw_Ib(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Iw, &Instruction::decode_Ib>(buf, size); }
	void decode_Gz_Mp(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gz, &Instruction::decode_Mp>(buf, size); }
	void decode_Gv_M(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_M>(buf, size); }
	void decode_Gv_Ma(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_Ma>(buf, size); }
	void decode_Gb_Eb(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gb, &Instruction::decode_Eb>(buf, size); }
	void decode_Gv_Eb(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_Eb>(buf, size); }
	void decode_Gv_Ev(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_Ev>(buf, size); }
	void decode_Eb_Gb(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Eb, &Instruction::decode_Gb>(buf, size); }
	void decode_Ew_Gw(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ew, &Instruction::decode_Gw>(buf, size); }
	void decode_Ev_Gv(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Ev, &Instruction::decode_Gv>(buf, size); }
	void decode_Gv_Ew(const uint8_t *buf, std::size_t size)			{ decode2<&Instruction::decode_Gv, &Instruction::decode_Ew>(buf, size); }
	void decode_Pq_Ed(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Pq, &Instruction::decode_Ed>(buf, size); }
	void decode_Pq_Qd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Pq, &Instruction::decode_Qd>(buf, size); }
	void decode_Pq_Qq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Pq, &Instruction::decode_Qq>(buf, size); }
	void decode_Qq_Pq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Qq, &Instruction::decode_Pq>(buf, size); }
	void decode_Vd_Wd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vd, &Instruction::decode_Wd>(buf, size); }
	void decode_Vo_Wq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Wq>(buf, size); }
	void decode_Vq_Mq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vq, &Instruction::decode_Mq>(buf, size); }
	void decode_Mq_Vq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Mq, &Instruction::decode_Vq>(buf, size); }
	void decode_Ed_Pd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Ed, &Instruction::decode_Pd>(buf, size); }
	void decode_Md_Gd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Md, &Instruction::decode_Gd>(buf, size); }
	void decode_Pq_PRq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Pq, &Instruction::decode_PRq>(buf, size); }
	void decode_Wd_Vd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Wd, &Instruction::decode_Vd>(buf, size); }
	void decode_Vd_Ed(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vd, &Instruction::decode_Ed>(buf, size); }
	void decode_Gd_Wd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Gd, &Instruction::decode_Wd>(buf, size); }
	void decode_Md_Vd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Md, &Instruction::decode_Vd>(buf, size); }
	void decode_Vo_Mq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Mq>(buf, size); }
	void decode_Vo_PRq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_PRq>(buf, size); }
	void decode_Vq_Wq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vq, &Instruction::decode_Wq>(buf, size); }
	void decode_Vo_Ed(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Ed>(buf, size); }
	void decode_Vo_Vo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Vo>(buf, size); }
	void decode_Vo_VRo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_VRo>(buf, size); }
	void decode_Wq_Vq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Wq, &Instruction::decode_Vq>(buf, size); }
	void decode_Gd_Wq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Gd, &Instruction::decode_Wq>(buf, size); }
	void decode_Vq_Ed(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vq, &Instruction::decode_Ed>(buf, size); }
	void decode_Vo_Mo(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Vo, &Instruction::decode_Mo>(buf, size); }
	void decode_Pq_VRq(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Pq, &Instruction::decode_VRq>(buf, size); }	
	void decode_Ed_Gd(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Ed, &Instruction::decode_Gd>(buf, size); }
	void decode_Gd_Ed(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_Gd, &Instruction::decode_Ed>(buf, size); }
	void decode_PRq_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_PRq, &Instruction::decode_Ib>(buf, size); }
	void decode_VRo_Ib(const uint8_t *buf, std::size_t size) 		{ decode2<&Instruction::decode_VRo, &Instruction::decode_Ib>(buf, size); }
	
private:
	// 3 operand modes
	void decode_Pq_Ew_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Pq, &Instruction::decode_Ew, &Instruction::decode_Ib>(buf, size); }
	void decode_Gv_Ev_Iz(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Gv, &Instruction::decode_Ev, &Instruction::decode_Iz>(buf, size); }
	void decode_Gv_Ev_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Gv, &Instruction::decode_Ev, &Instruction::decode_Ib>(buf, size); }
	void decode_Ev_Gv_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Ev, &Instruction::decode_Gv, &Instruction::decode_Ib>(buf, size); }
	void decode_Vo_Wo_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Vo, &Instruction::decode_Wo, &Instruction::decode_Ib>(buf, size); }
	void decode_Gd_PRq_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Gd, &Instruction::decode_PRq, &Instruction::decode_Ib>(buf, size); }
	void decode_Pq_Qq_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Pq, &Instruction::decode_Qq, &Instruction::decode_Ib>(buf, size); }
	void decode_Vd_Wd_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Vd, &Instruction::decode_Wd, &Instruction::decode_Ib>(buf, size); }
	void decode_Vo_Mw_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Vo, &Instruction::decode_Mw, &Instruction::decode_Ib>(buf, size); }
	void decode_Gd_VRo_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Gd, &Instruction::decode_VRo, &Instruction::decode_Ib>(buf, size); }
	void decode_Vq_Wq_Ib(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Vq, &Instruction::decode_Wq, &Instruction::decode_Ib>(buf, size); }
	
	template<Operand::Register REG>
	void decode_Ev_Gv_Reg(const uint8_t *buf, std::size_t size)	{ decode3<&Instruction::decode_Ev, &Instruction::decode_Gv, &Instruction::decode_Reg<REG> >(buf, size); }

private:
	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 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 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_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 Operand &operand(std::size_t index) const	{ return m_Operands[index]; }

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


private:
	friend class Operand;
	
	Operand	m_Operands[3];
	
	union {
		uint16_t m_IP;
		uint32_t m_EIP;
		uint64_t m_RIP;
	};
	
	OpcodeEntry *m_Opcode;
	const char *m_Mnemonic;
	Type m_Type;
	
	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;
};

#endif

