/* * Realmode Emulator Plugin * - By John Hodge (thePowersGang) * * This code is published under the FreeBSD licence * (See the file COPYING for details) * * --- * Core Emulator Include */ #ifndef _RME_H_ #define _RME_H_ /** * \file rme.h * \brief Realmode Emulator Header * \author John Hodge (thePowersGang) * * \section using Using RME * */ /** * \brief Enable the use of size overrides * \note Disabling this will speed up emulation, but may cause undefined * behavior with some BIOSes. * * If set to -1, size overrides will cause a \#UD */ #define USE_SIZE_OVERRIDES 1 /** * \brief Size of a memory block * \note Feel free to edit this value, just make sure it stays a power * of two. */ #define RME_BLOCK_SIZE 0x1000 /** * \brief Magic return Instruction Pointer */ #define RME_MAGIC_IP 0xFFFF /** * \brief Magic return Code Segment */ #define RME_MAGIC_CS 0xFFFF /** * \brief Error codes returned by ::RME_Call and ::RME_CallInt */ enum eRME_Errors { RME_ERR_OK, //!< Exited successfully RME_ERR_INVAL, //!< Bad paramater passed to emulator RME_ERR_BADMEM, //!< Emulator accessed invalid memory RME_ERR_UNDEFOPCODE, //!< Undefined opcode RME_ERR_DIVERR, //!< Divide error RME_ERR_BUG, //!< Bug in the emulator RME_ERR_LAST //!< Last Error }; typedef union uGPR { #if USE_SIZE_OVERRIDES == 1 uint32_t D; #endif uint16_t W; struct { uint8_t L; uint8_t H; } B; } tGPR; /** * \brief Emulator state structure */ typedef struct sRME_State { //! \brief General Purpose Registers //! \{ tGPR AX, CX, DX, BX, SP, BP, SI, DI; //! \} //! \brief Segment Registers //! \{ uint16_t SS; //!< Stack Segment uint16_t DS; //!< Data Segment uint16_t ES; //!< Extra Segment //! \} //! \brief Program Counter //! \{ uint16_t CS; //!< Code Segment uint16_t IP; //!< Instruction Pointer //! \} uint16_t Flags; //!< State Flags /** * \brief Emulator's Memory * * The ~1MiB realmode address space is broken into blocks of * ::RME_BLOCK_SIZE bytes that can each point to different areas * of memory. * NOTE: There is no write protection on these blocks * \note A value of NULL in a block indicates that the block is invalid * \note 0x110000 bytes is all that is accessable using the realmode * segmentation scheme (true max is 0xFFFF0+0xFFFF = 0x10FFEF) */ uint8_t *Memory[0x110000/RME_BLOCK_SIZE]; // 1Mib,64KiB in 256 4 KiB blocks /** * \brief High-Level Emulation Callback * \param State Emulation state at the interrupt * \param IntNum Interrupt number * \return 1 if the call was handled, 0 if it should be emulated * * Called on all in-emulator INT calls */ int (*HLECallbacks[256])(struct sRME_State *State, int IntNum); int InstrNum; //!< Total executed instructions // --- Decoder State --- /** * \brief Decoder State * \note Should not be touched except by the emulator */ struct { int OverrideSegment; int bOverrideOperand; int bOverrideAddress; int IPOffset; } Decoder; } tRME_State; /** * \brief Creates a blank RME instance */ extern tRME_State *RME_CreateState(void); /** * \brief Calls an interrupt * \param State State returned from ::RME_CreateState * \param Num Interrupt number */ extern int RME_CallInt(tRME_State *State, int Num); /** * \brief Executes the emulator until RME_MAGIC_CS:RME_MAGIC_IP is reached * \param State State returned from ::RME_CreateState */ extern int RME_Call(tRME_State *State); /** * \brief Prints contents of the state's registers to debug * \param State State returned from ::RME_CreateState */ extern void RME_DumpRegs(tRME_State *State); /* * Definitions specific to the internals of the emulator */ #ifdef _RME_C_ /** */ enum gpRegs { AL, CL, DL, BL, AH, CH, DH, BH }; enum sRegs { SREG_ES, SREG_CS, SREG_SS, SREG_DS }; #define OPCODE_RI(name, code) name##_RI_AL = code|AL, name##_RI_BL = code|BL,\ name##_RI_CL = code|CL, name##_RI_DL = code|DL,\ name##_RI_AH = code|AH, name##_RI_BH = code|BH,\ name##_RI_CH = code|CH, name##_RI_DH = code|DH,\ name##_RI_AX = code|AL|8, name##_RI_BX = code|BL|8,\ name##_RI_CX = code|CL|8, name##_RI_DX = code|DL|8,\ name##_RI_SP = code|AH|8, name##_RI_BP = code|CH|8,\ name##_RI_SI = code|DH|8, name##_RI_DI = code|BH|8 enum opcodes { ADD_MR = 0x00, ADD_MRX = 0x01, ADD_RM = 0x02, ADD_RMX = 0x03, ADD_AI = 0x04, ADD_AIX = 0x05, OR_MR = 0x08, OR_MRX = 0x09, OR_RM = 0x0A, OR_RMX = 0x0B, OR_AI = 0x0C, OR_AIX = 0x0D, AND_MR = 0x20, AND_MRX = 0x21, AND_RM = 0x22, AND_RMX = 0x23, AND_AI = 0x24, AND_AIX = 0x25, SUB_MR = 0x28, SUB_MRX = 0x29, SUB_RM = 0x2A, SUB_RMX = 0x2B, SUB_AI = 0x2C, SUB_AIX = 0x2D, XOR_MR = 0x30, XOR_MRX = 0x31, XOR_RM = 0x32, XOR_RMX = 0x33, XOR_AI = 0x34, XOR_AIX = 0x35, CMP_MR = 0x38, CMP_MRX = 0x39, CMP_RM = 0x3A, CMP_RMX = 0x3B, CMP_AI = 0x3C, CMP_AIX = 0x3D, DEC_A = 0x48|AL, DEC_B = 0x48|BL, DEC_C = 0x48|CL, DEC_D = 0x48|DL, DEC_Sp = 0x48|AH, DEC_Bp = 0x48|CH, DEC_Si = 0x48|DH, DEC_Di = 0x48|BH, INC_A = 0x40|AL, INC_B = 0x40|BL, INC_C = 0x40|CL, INC_D = 0x40|DL, INC_Sp = 0x40|AH, INC_Bp = 0x40|CH, INC_Si = 0x40|DH, INC_Di = 0x40|BH, DIV_R = 0xFA, DIV_RX = 0xFB, DIV_M = 0xFA, DIV_MX = 0xFB, INT3 = 0xCC, INT_I = 0xCD, IRET = 0xCF, MOV_MoA = 0xA2, MOV_MoAX = 0xA3, MOV_AMo = 0xA0, MOV_AMoX = 0xA1, OPCODE_RI(MOV, 0xB0), MOV_MI = 0xC6, MOV_MIX = 0xC7, MOV_MR = 0x88, MOV_MRX = 0x89, MOV_RM = 0x8A, MOV_RMX = 0x8B, MOV_RS = 0x8C, MOV_SR = 0x8E, MOV_MS = 0x8C, MOV_SM = 0x8E, MUL_R = 0xF6, MUL_RX = 0xF7, MUL_M = 0xF6, MUL_MX = 0xF7, NOP = 0x90, XCHG_AA = 0x90, XCHG_AB = 0x90|BL, XCHG_AC = 0x90|CL, XCHG_AD = 0x90|DL, XCHG_ASp = 0x90|AH, XCHG_ABp = 0x90|CH, XCHG_ASi = 0x90|DH, XCHG_ADi = 0x90|BH, XCHG_RM = 0x86, NOT_R = 0xF6, NOT_RX = 0xF7, NOT_M = 0xF6, NOT_MX = 0xF7, IN_AI = 0xE4, IN_AIX = 0xE5, IN_ADx = 0xEC, IN_ADxX = 0xED, OUT_IA = 0xE6, OUT_IAX = 0xE7, OUT_DxA = 0xEE, OUT_DxAX = 0xEF, POP_AX = 0x58|AL, POP_BX = 0x58|BL, POP_CX = 0x58|CL, POP_DX = 0x58|DL, POP_SP = 0x58|AH, POP_BP = 0x58|CH, POP_SI = 0x58|DH, POP_DI = 0x58|BH, POP_ES = 7|(SREG_ES<<3), POP_SS = 7|(SREG_SS<<3), POP_DS = 7|(SREG_DS<<3), POP_MX = 0x8F, POPA = 0x61, POPF = 0x9D, PUSH_AX = 0x50|AL, PUSH_BX = 0x50|BL, PUSH_CX = 0x50|CL, PUSH_DX = 0x50|DL, PUSH_SP = 0x50|AH, PUSH_BP = 0x50|CH, PUSH_SI = 0x50|DH, PUSH_DI = 0x50|BH, // PUSH_MX = 0xFF, // - TODO: Check (maybe 0x87) PUSH_ES = 6|(SREG_ES<<3), PUSH_CS = 6|(SREG_CS<<3), PUSH_SS = 6|(SREG_SS<<3), PUSH_DS = 6|(SREG_DS<<3), PUSH_I8 = 0x6A, PUSH_I = 0x68, PUSHA = 0x60, PUSHF = 0x9C, RET_N = 0xC3, RET_iN = 0xC2, RET_F = 0xCB, RET_iF = 0xCA, CALL_MF = 0xFF, CALL_MN = 0xFF, CALL_N = 0xE8, CALL_F = 0x9A, CALL_R = 0xFF, JMP_MF = 0xFF, JMP_N = 0xE9, JMP_S = 0xEB, JMP_F = 0xEA, LES = 0xC4, LDS = 0xC5, LEA = 0x8D, CLC = 0xF8, STC = 0xF9, CLI = 0xFA, STI = 0xFB, CLD = 0xFC, STD = 0xFD, TEST_RM = 0x84, TEST_RMX = 0x85, TEST_AI = 0xA8, TEST_AIX = 0xA9, MOVSB = 0xA4, MOVSW = 0xA5, CMPSB = 0xA6, CMPSW = 0xA7, STOSB = 0xAA, STOSW = 0xAB, LODSB = 0xAC, LODSW = 0xAD, SCASB = 0xAE, SCASW = 0xAF, INSB = 0x6C, INSW = 0x6D, OUTSB = 0x6E, OUTSW = 0x6F, // --- Unimplementeds FPU_ARITH = 0xDC, // --- Overrides OVR_ES = 0x26, OVR_CS = 0x2E, OVR_SS = 0x36, OVR_DS = 0x3E, REPNZ = 0xF2, REP = 0xF3, LOOPNZ = 0xE0, LOOPZ = 0xE1, LOOP = 0xE2 }; #endif #endif