From 5f874178e7939c1956c1b005c814cc812b51f424 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Wed, 4 Sep 2013 01:11:12 +0000 Subject: [PATCH] [SOFT386] Implement helper functions for reading/writing operands of instructions that use the MOD-REG-R/M byte. Implement the MOD-REG-R/M ADD instruction for bytes. svn path=/branches/ntvdm/; revision=59981 --- lib/soft386/common.c | 300 ++++++++++++++++++++++++++++++++++++++++++ lib/soft386/common.h | 60 +++++++++ lib/soft386/opcodes.c | 65 ++++++++- lib/soft386/opcodes.h | 9 ++ 4 files changed, 432 insertions(+), 2 deletions(-) diff --git a/lib/soft386/common.c b/lib/soft386/common.c index 6a0b772f6ad..b142f8dec64 100644 --- a/lib/soft386/common.c +++ b/lib/soft386/common.c @@ -987,4 +987,304 @@ Soft386ParseModRegRm(PSOFT386_STATE State, return TRUE; } +inline +BOOLEAN +Soft386ReadModrmByteOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PUCHAR RegValue, + PUCHAR RmValue) +{ + INT Segment = SOFT386_REG_DS; + + /* Get the register value */ + if (ModRegRm->Register & 0x04) + { + /* AH, CH, DH, BH */ + *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte; + } + else + { + /* AL, CL, DL, BL */ + *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte; + } + + if (!ModRegRm->Memory) + { + /* Get the second register value */ + if (ModRegRm->SecondRegister & 0x04) + { + /* AH, CH, DH, BH */ + *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte; + } + else + { + /* AL, CL, DL, BL */ + *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte; + } + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Read memory */ + if (!Soft386ReadMemory(State, + Segment, + ModRegRm->MemoryAddress, + FALSE, + RmValue, + sizeof(UCHAR))) + { + /* Exception occurred */ + return FALSE; + } + } + + return TRUE; +} + +inline +BOOLEAN +Soft386ReadModrmWordOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PUSHORT RegValue, + PUSHORT RmValue) +{ + INT Segment = SOFT386_REG_DS; + + /* Get the register value */ + *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord; + + if (!ModRegRm->Memory) + { + /* Get the second register value */ + *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord; + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Read memory */ + if (!Soft386ReadMemory(State, + Segment, + ModRegRm->MemoryAddress, + FALSE, + RmValue, + sizeof(USHORT))) + { + /* Exception occurred */ + return FALSE; + } + } + + return TRUE; +} + +inline +BOOLEAN +Soft386ReadModrmDwordOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PULONG RegValue, + PULONG RmValue) +{ + INT Segment = SOFT386_REG_DS; + + /* Get the register value */ + *RegValue = State->GeneralRegs[ModRegRm->Register].Long; + + if (!ModRegRm->Memory) + { + /* Get the second register value */ + *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long; + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Read memory */ + if (!Soft386ReadMemory(State, + Segment, + ModRegRm->MemoryAddress, + FALSE, + RmValue, + sizeof(ULONG))) + { + /* Exception occurred */ + return FALSE; + } + } + + return TRUE; +} + +inline +BOOLEAN +Soft386WriteModrmByteOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + UCHAR Value) +{ + INT Segment = SOFT386_REG_DS; + + if (WriteRegister) + { + /* Store the value in the register */ + if (ModRegRm->Register & 0x04) + { + /* AH, CH, DH, BH */ + State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value; + } + else + { + /* AL, CL, DL, BL */ + State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value; + } + } + else + { + if (!ModRegRm->Memory) + { + /* Store the value in the second register */ + if (ModRegRm->SecondRegister & 0x04) + { + /* AH, CH, DH, BH */ + State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value; + } + else + { + /* AL, CL, DL, BL */ + State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value; + } + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Write memory */ + if (!Soft386WriteMemory(State, + Segment, + ModRegRm->MemoryAddress, + &Value, + sizeof(UCHAR))) + { + /* Exception occurred */ + return FALSE; + } + } + } + + return TRUE; +} + +inline +BOOLEAN +Soft386WriteModrmWordOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + USHORT Value) +{ + INT Segment = SOFT386_REG_DS; + + if (WriteRegister) + { + /* Store the value in the register */ + State->GeneralRegs[ModRegRm->Register].LowWord = Value; + } + else + { + if (!ModRegRm->Memory) + { + /* Store the value in the second register */ + State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value; + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Write memory */ + if (!Soft386WriteMemory(State, + Segment, + ModRegRm->MemoryAddress, + &Value, + sizeof(USHORT))) + { + /* Exception occurred */ + return FALSE; + } + } + } + + return TRUE; +} + +inline +BOOLEAN +Soft386WriteModrnDwordOperands(PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + ULONG Value) +{ + INT Segment = SOFT386_REG_DS; + + if (WriteRegister) + { + /* Store the value in the register */ + State->GeneralRegs[ModRegRm->Register].Long = Value; + } + else + { + if (!ModRegRm->Memory) + { + /* Store the value in the second register */ + State->GeneralRegs[ModRegRm->SecondRegister].Long = Value; + } + else + { + /* Check for the segment override */ + if (State->PrefixFlags & SOFT386_PREFIX_SEG) + { + /* Use the override segment instead */ + Segment = State->SegmentOverride; + } + + /* Write memory */ + if (!Soft386WriteMemory(State, + Segment, + ModRegRm->MemoryAddress, + &Value, + sizeof(ULONG))) + { + /* Exception occurred */ + return FALSE; + } + } + } + + return TRUE; +} + /* EOF */ diff --git a/lib/soft386/common.h b/lib/soft386/common.h index f5f454321b5..79a6cf91831 100644 --- a/lib/soft386/common.h +++ b/lib/soft386/common.h @@ -149,6 +149,66 @@ Soft386ParseModRegRm PSOFT386_MOD_REG_RM ModRegRm ); +inline +BOOLEAN +Soft386ReadModrmByteOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PUCHAR RegValue, + PUCHAR RmValue +); + +inline +BOOLEAN +Soft386ReadModrmWordOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PUSHORT RegValue, + PUSHORT RmValue +); + +inline +BOOLEAN +Soft386ReadModrmDwordOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + PULONG RegValue, + PULONG RmValue +); + +inline +BOOLEAN +Soft386WriteModrmByteOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + UCHAR Value +); + +inline +BOOLEAN +Soft386WriteModrmWordOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + USHORT Value +); + +inline +BOOLEAN +Soft386WriteModrnDwordOperands +( + PSOFT386_STATE State, + PSOFT386_MOD_REG_RM ModRegRm, + BOOLEAN WriteRegister, + ULONG Value +); + #endif // _COMMON_H_ /* EOF */ diff --git a/lib/soft386/opcodes.c b/lib/soft386/opcodes.c index 7da7620ae72..318b3ca38c0 100644 --- a/lib/soft386/opcodes.c +++ b/lib/soft386/opcodes.c @@ -24,9 +24,9 @@ SOFT386_OPCODE_HANDLER_PROC Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] = { - NULL, // TODO: OPCODE 0x00 NOT SUPPORTED + Soft386OpcodeAddByteModrm, // TODO: OPCODE 0x00 NOT SUPPORTED NULL, // TODO: OPCODE 0x01 NOT SUPPORTED - NULL, // TODO: OPCODE 0x02 NOT SUPPORTED + Soft386OpcodeAddByteModrm, // TODO: OPCODE 0x02 NOT SUPPORTED NULL, // TODO: OPCODE 0x03 NOT SUPPORTED NULL, // TODO: OPCODE 0x04 NOT SUPPORTED NULL, // TODO: OPCODE 0x05 NOT SUPPORTED @@ -1258,3 +1258,64 @@ Soft386OpcodeMovByteRegImm(PSOFT386_STATE State, UCHAR Opcode) return TRUE; } + +BOOLEAN +FASTCALL +Soft386OpcodeAddByteModrm(PSOFT386_STATE State, UCHAR Opcode) +{ + UCHAR FirstValue, SecondValue, Result; + SOFT386_MOD_REG_RM ModRegRm; + BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + /* Make sure this is the right instruction */ + ASSERT((Opcode & 0xFD) == 0x00); + + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the size */ + AddressSize = !AddressSize; + } + else if (State->PrefixFlags + & ~(SOFT386_PREFIX_ADSIZE + | SOFT386_PREFIX_SEG + | SOFT386_PREFIX_LOCK)) + { + /* Invalid prefix */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Soft386ReadModrmByteOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Calculate the result */ + Result = FirstValue + SecondValue; + + /* Update the flags */ + State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue); + State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE)) + && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE)); + State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE; + State->Flags.Zf = (Result == 0) ? TRUE : FALSE; + State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE; + State->Flags.Pf = Soft386CalculateParity(Result); + + /* Write back the result */ + return Soft386WriteModrmByteOperands(State, + &ModRegRm, + Opcode & SOFT386_OPCODE_WRITE_REG, + Result); +} diff --git a/lib/soft386/opcodes.h b/lib/soft386/opcodes.h index dd7cc675dc9..1213941a438 100644 --- a/lib/soft386/opcodes.h +++ b/lib/soft386/opcodes.h @@ -16,6 +16,7 @@ #endif #define SOFT386_NUM_OPCODE_HANDLERS 256 +#define SOFT386_OPCODE_WRITE_REG (1 << 1) typedef BOOLEAN (FASTCALL *SOFT386_OPCODE_HANDLER_PROC)(PSOFT386_STATE, UCHAR); @@ -207,4 +208,12 @@ Soft386OpcodeMovByteRegImm UCHAR Opcode ); +BOOLEAN +FASTCALL +Soft386OpcodeAddByteModrm +( + PSOFT386_STATE State, + UCHAR Opcode +); + #endif // _OPCODES_H_