[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
This commit is contained in:
Aleksandar Andrejevic 2013-09-04 01:11:12 +00:00
parent 6f2f5335c2
commit 5f874178e7
4 changed files with 432 additions and 2 deletions

View file

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

View file

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

View file

@ -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);
}

View file

@ -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_