/*
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 OPERAND_20070521_H_
#define OPERAND_20070521_H_

#include <stdint.h>
#include <string>

class Instruction;

class Operand {
public:
	Operand();
	friend class Instruction;

public:
	enum Register {
		REG_NONE,
		
		REG_EAX, REG_ECX, REG_EDX, REG_EBX,
		REG_ESP, REG_EBP, REG_ESI, REG_EDI,
		
		REG_AX, REG_CX, REG_DX, REG_BX,
		REG_SP, REG_BP, REG_SI, REG_DI,
		
		REG_AL, REG_CL, REG_DL, REG_BL,
		REG_AH, REG_CH, REG_DH, REG_BH,
		
		REG_ES, REG_CS, REG_SS, REG_DS,
		REG_FS, REG_GS, REG_SEG7, REG_SEG8,
		
		REG_CR0, REG_CR1, REG_CR2, REG_CR3,
		REG_CR4, REG_CR5, REG_CR6, REG_CR7,
		
		REG_DR0, REG_DR1, REG_DR2, REG_DR3,
		REG_DR4, REG_DR5, REG_DR6, REG_DR7,
		
		REG_TR0, REG_TR1, REG_TR2, REG_TR3,
		REG_TR4, REG_TR5, REG_TR6, REG_TR7,
		
		REG_MM0, REG_MM1, REG_MM2, REG_MM3,
		REG_MM4, REG_MM5, REG_MM6, REG_MM7,
		
		REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3,
		REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7,	
		
		REG_ST,
		REG_ST0, REG_ST1, REG_ST2, REG_ST3,
		REG_ST4, REG_ST5, REG_ST6, REG_ST7,
	};

	enum Type {
		TYPE_INVALID		= 0x00000000,
		TYPE_REGISTER		= 0x00000100,
		TYPE_IMMEDIATE		= 0x00000200,
		TYPE_IMMEDIATE8		= 0x00000201,
		TYPE_IMMEDIATE16	= 0x00000202,
		TYPE_IMMEDIATE32	= 0x00000203,
		TYPE_IMMEDIATE64	= 0x00000204,
		TYPE_REL			= 0x00000300,
		TYPE_REL8			= 0x00000301,
		TYPE_REL16			= 0x00000302,
		TYPE_REL32			= 0x00000303,
		TYPE_EXPRESSION		= 0x00000400,
		TYPE_EXPRESSION8	= 0x00000401,
		TYPE_EXPRESSION16	= 0x00000402,
		TYPE_EXPRESSION32	= 0x00000403,
		TYPE_EXPRESSION48	= 0x00000404,
		TYPE_EXPRESSION64	= 0x00000405,
		TYPE_EXPRESSION80	= 0x00000406,
		TYPE_EXPRESSION128	= 0x00000407,
		TYPE_ABSOLUTE		= 0x00000500,
		TYPE_MASK			= 0xffffff00
	} m_Type;


	enum DisplacementType {
		DISP_NONE,
		DISP_U8,
		DISP_U16,
		DISP_U32,
		DISP_S8,
		DISP_S16,
		DISP_S32
	};

	union {
		int8_t		sbyte;
		int16_t		sword;
		int32_t		sdword;
		int64_t		sqword;
		uint8_t		byte;
		uint16_t	word;
		uint32_t	dword;
		uint64_t	qword;
		Register	reg;
		
		struct {
			uint16_t seg;
			uint32_t offset;
		} absolute;


		struct {
			union {
				int8_t		s_disp8;
				int16_t		s_disp16;
				int32_t		s_disp32;
				uint8_t		u_disp8;
				uint16_t	u_disp16;
				uint32_t	u_disp32;
			};
			Register			base;
			Register			index;
			uint8_t				scale;
			DisplacementType	displacement_type;
		} expression;
	};
	
private:
	Instruction *m_Owner;
	
public:
	std::string formatImmediate() const;
	std::string formatRelative() const;
	std::string formatExpression() const;
	std::string formatAbsolute() const;
	std::string format() const;
	
public:
	Instruction *owner() const { return m_Owner; }
	int32_t displacement() const;
	Type generalType() const;
	Type completeType() const { return m_Type; }
	bool valid() const { return m_Type != TYPE_INVALID; }
	
public:
	static std::string registerName(Register reg) { return RegisterName[reg]; }
	
private:
	static const char *RegisterName[];
};

#endif

