toaruos/kernel/v8086/rme.h

330 lines
7.2 KiB
C
Raw Normal View History

/*
* 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