#ifndef __BOCHS_CPU_HPP__
#define __BOCHS_CPU_HPP__

#include "../x86/X86Architecture.hpp"
#include "../x86/X86CPUState.hpp"

#include "bochs.h"
#include "cpu/cpu.h"

namespace fail {

/**
 * \class BochsCPU
 *
 * \c BochsCPU is the concrete CPU implementation for the Bochs x86 simulator. It
 * implements the CPU interfaces \c X86Architecture and \c X86CPUState.
 * \c X86Architecture refers to architectural information (e.g. register \a count)
 * while \c X86CPUState encapsulates the CPU state (e.g. register \a content).
 *
 */
class BochsCPU : public X86Architecture, public X86CPUState {
private:
	unsigned int m_Id; //!< the numeric CPU identifier (ID)
public:
	/**
	 * Initializes the Bochs CPU with the provided \c id.
	 * @param id the CPU identifier (the 1st CPU is CPU0 -> id = 0, and so forth)
	 */
	BochsCPU(unsigned int id) : m_Id(id) { }
	/**
	 * Virtual Destructor is required.
	 */
	virtual ~BochsCPU() { }
		/**
	 * Retrieves the content of the register \c reg.
	 * @param reg the register pointer of interest (cannot be \c NULL)
	 * @return the content of the register \c reg
	 */
	regdata_t getRegisterContent(const Register* reg) const;
	/**
	 * Sets the content of the register \c reg to \c value.
	 * @param reg the destination register object pointer (cannot be \c NULL)
	 * @param value the new value to assign
	 */
	void setRegisterContent(const Register* reg, regdata_t value);
	/**
	 * Returns the current instruction pointer (aka program counter).
	 * @return the current (e)ip register content
	 */
	address_t getInstructionPointer() const { return getRegisterContent(getRegister(RID_PC)); }
	/**
	 * Returns the current stack pointer.
	 * @return the current (e)sp register content
	 */
	address_t getStackPointer() const { return getRegisterContent(getRegister(RID_CSP)); }
	/**
	 * Returns the current base pointer.
	 * @return the current (e)bp register content
	 */
	address_t getBasePointer() const { return getRegisterContent(getRegister(RID_CBP)); }
	/**
	 * Returns the current (E)FLAGS.
	 * @return the current (E)FLAGS processor register content
	 */
	regdata_t getFlagsRegister() const { return getRegisterContent(getRegister(RID_FLAGS)); }
	/**
	 * Returns \c true if the corresponding flag is set, or \c false
	 * otherwise.
	 */
	bool getCarryFlag() const             { return BX_CPU(0)->get_CF();   }
	bool getParityFlag() const            { return BX_CPU(0)->get_PF();   }
	bool getZeroFlag() const              { return BX_CPU(0)->get_ZF();   }
	bool getSignFlag() const              { return BX_CPU(0)->get_SF();   }
	bool getOverflowFlag() const          { return BX_CPU(0)->get_OF();   }
	bool getTrapFlag() const              { return BX_CPU(0)->get_TF();   }
	bool getInterruptFlag() const         { return BX_CPU(0)->get_IF();   }
	bool getDirectionFlag() const         { return BX_CPU(0)->get_DF();   }
	unsigned getIOPrivilegeLevel() const  { return BX_CPU(0)->get_IOPL(); }
	bool getNestedTaskFlag() const        { return BX_CPU(0)->get_NT();   }
	bool getResumeFlag() const            { return BX_CPU(0)->get_RF();   }
	bool getVMFlag() const                { return BX_CPU(0)->get_VM();   }
	bool getAlignmentCheckFlag() const    { return BX_CPU(0)->get_AC();   }
	bool getVInterruptFlag() const        { return BX_CPU(0)->get_VIF();  }
	bool getVInterruptPendingFlag() const { return BX_CPU(0)->get_VIP();  }
	bool getIdentificationFlag() const    { return BX_CPU(0)->get_ID();   }
	/**
	 * Sets/resets various status FLAGS.
	 */
	void setCarryFlag(bool bit)             { BX_CPU(0)->set_CF(bit);   }
	void setParityFlag(bool bit)            { BX_CPU(0)->set_PF(bit);   }
	void setZeroFlag(bool bit)              { BX_CPU(0)->set_ZF(bit);   }
	void setSignFlag(bool bit)              { BX_CPU(0)->set_SF(bit);   }
	void setOverflowFlag(bool bit)          { BX_CPU(0)->set_OF(bit);   }
	void setTrapFlag(bool bit)              { BX_CPU(0)->set_TF(bit);   }
	void setInterruptFlag(bool bit)         { BX_CPU(0)->set_IF(bit);   }
	void setDirectionFlag(bool bit)         { BX_CPU(0)->set_DF(bit);   }
	void setIOPrivilegeLevel(unsigned lvl)  { BX_CPU(0)->set_IOPL(lvl); }
	void setNestedTaskFlag(bool bit)        { BX_CPU(0)->set_NT(bit);   }
	void setResumeFlag(bool bit)            { BX_CPU(0)->set_RF(bit);   }
	void setVMFlag(bool bit)                { BX_CPU(0)->set_VM(bit);   }
	void setAlignmentCheckFlag(bool bit)    { BX_CPU(0)->set_AC(bit);   }
	void setVInterruptFlag(bool bit)        { BX_CPU(0)->set_VIF(bit);  }
	void setVInterruptPendingFlag(bool bit) { BX_CPU(0)->set_VIP(bit);  }
	void setIdentificationFlag(bool bit)    { BX_CPU(0)->set_ID(bit);   }
	/**
	 * Returns the current id of this CPU.
	 * @return the current id
	 */
	unsigned int getId() const { return m_Id; }
};

typedef BochsCPU ConcreteCPU; //!< the concrete BochsCPU type

} // end-of-namespace: fail

#endif // __BOCHS_CPU_HPP__
