ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg)
{
- if ((State->PrefixFlags != SOFT386_PREFIX_OPSIZE)
- && (State->PrefixFlags != 0))
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
INT Reg = Opcode & 0x07;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF7) == 0xE5);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF7) == 0xE7);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF8) == 0xB8);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs)
-{
- /* Call the internal API */
- return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_DS].Selector);
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs)
-{
- ULONG NewSelector;
-
- if (!Soft386StackPop(State, &NewSelector))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Call the internal API */
- return Soft386LoadSegment(State, SOFT386_REG_DS, LOWORD(NewSelector));
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa)
-{
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- BOOLEAN Carry = State->Flags.Cf;
-
- /* Clear the carry flag */
- State->Flags.Cf = FALSE;
-
- /* Check if the first BCD digit is invalid or there was a carry from it */
- if (((Value & 0x0F) > 9) || State->Flags.Af)
- {
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
- if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
- {
- /* A carry occurred */
- State->Flags.Cf = TRUE;
- }
-
- /* Set the adjust flag */
- State->Flags.Af = TRUE;
- }
-
- /* Check if the second BCD digit is invalid or there was a carry from it */
- if ((Value > 0x99) || Carry)
- {
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
-
- /* There was a carry */
- State->Flags.Cf = TRUE;
- }
-
- return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
{
UCHAR FirstValue, SecondValue, Result;
SOFT386_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xED) == 0x28);
+ ASSERT((Opcode & 0xFD) == 0x18);
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))
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + 1);
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);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmByteOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm)
{
SOFT386_MOD_REG_RM ModRegRm;
BOOLEAN OperandSize, AddressSize;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xED) == 0x29);
+ ASSERT((Opcode & 0xFD) == 0x19);
OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
OperandSize = !OperandSize;
}
- if (State->PrefixFlags
- & ~(SOFT386_PREFIX_ADSIZE
- | SOFT386_PREFIX_OPSIZE
- | SOFT386_PREFIX_SEG
- | SOFT386_PREFIX_LOCK))
- {
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Get the operands */
if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
ULONG FirstValue, SecondValue, Result;
if (!Soft386ReadModrmDwordOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
/* Exception occurred */
return FALSE;
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
&& ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
else
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
&& ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmWordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
-
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl)
{
UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
UCHAR SecondValue, Result;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xEF) == 0x2C);
+ ASSERT(Opcode == 0x1C);
if (State->PrefixFlags)
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
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);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
- }
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
return TRUE;
+
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax)
{
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xEF) == 0x2D);
+ ASSERT(Opcode == 0x1D);
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
&& ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
- }
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
}
else
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
&& ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
}
return TRUE;
+
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs)
{
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- BOOLEAN Carry = State->Flags.Cf;
+ /* Call the internal API */
+ return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_DS].Selector);
+}
- /* Clear the carry flag */
- State->Flags.Cf = FALSE;
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs)
+{
+ ULONG NewSelector;
- /* Check if the first BCD digit is invalid or there was a borrow */
- if (((Value & 0x0F) > 9) || State->Flags.Af)
+ if (!Soft386StackPop(State, &NewSelector))
{
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
- if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386LoadSegment(State, SOFT386_REG_DS, LOWORD(NewSelector));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Carry = State->Flags.Cf;
+
+ /* Clear the carry flag */
+ State->Flags.Cf = FALSE;
+
+ /* Check if the first BCD digit is invalid or there was a carry from it */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
+ {
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
+ if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
+ {
+ /* A carry occurred */
+ State->Flags.Cf = TRUE;
+ }
+
+ /* Set the adjust flag */
+ State->Flags.Af = TRUE;
+ }
+
+ /* Check if the second BCD digit is invalid or there was a carry from it */
+ if ((Value > 0x99) || Carry)
+ {
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
+
+ /* There was a carry */
+ State->Flags.Cf = TRUE;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
+{
+ 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 & 0xED) == 0x28);
+
+ 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;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < 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);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xED) == 0x29);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the address size */
+ AddressSize = !AddressSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_OPSIZE
+ | 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;
+ }
+
+ /* Check the operand size */
+ if (OperandSize)
+ {
+ ULONG FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+ }
+ else
+ {
+ USHORT FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xEF) == 0x2C);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < 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);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xEF) == 0x2D);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Carry = State->Flags.Cf;
+
+ /* Clear the carry flag */
+ State->Flags.Cf = FALSE;
+
+ /* Check if the first BCD digit is invalid or there was a borrow */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
+ {
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
+ if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
{
/* A borrow occurred */
State->Flags.Cf = TRUE;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x60);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x61);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x98);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x99);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ UCHAR Value;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
- return FALSE;
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* Read a byte from DS:[(E)BX + AL] */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EBX].Long
+ : State->GeneralRegs[SOFT386_REG_EBX].LowWord
+ + State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+ FALSE,
+ &Value,
+ sizeof(UCHAR)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Set AL to the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value;
+
+ /* Return success */
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop)
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xE8);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xE9);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ USHORT Segment = 0;
+ ULONG Offset = 0;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- return FALSE;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xEA);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Fetch the offset */
+ if (Size)
+ {
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+
+ /* Fetch the segment */
+ if (!Soft386FetchWord(State, &Segment))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Load the new CS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, Segment))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Load new (E)IP */
+ if (Size) State->InstPtr.Long = Offset;
+ else State->InstPtr.LowWord = LOWORD(Offset);
+
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
- /* Read from the source operand */
- if (!Soft386ReadMemory(State,
- SOFT386_REG_DS,
- AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
- : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
- FALSE,
- &Data,
- DataSize))
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- /* Exception occurred */
- return FALSE;
- }
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- /* Write to the destination operand */
- if (!Soft386WriteMemory(State,
- SOFT386_REG_ES,
- AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
- : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
- &Data,
- DataSize))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
- /* Increment/decrement ESI and EDI */
- if (OperandSize)
- {
- if (State->Flags.Df)
- {
- State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
- State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
- }
- else
+ /* Transfer until finished */
+ while (Count)
{
- State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
- State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytesSrc = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_ESI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_ESI].LowWord);
+ ULONG MaxBytesDest = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+
+ Processed = min(Processed, min(MaxBytesSrc, MaxBytesDest) / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ if (State->Flags.Df)
+ {
+ /* Reduce ESI and EDI by the number of bytes to transfer */
+ if (AddressSize)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long -= Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord -= Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+ }
+ }
+
+ /* Read from memory */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase ESI and EDI by the number of bytes transfered */
+ if (AddressSize)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long += Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord += Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
}
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- if (State->Flags.Df)
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &Data,
+ DataSize))
{
- State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
- State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &Data,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Increment/decrement ESI and EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
}
else
{
- State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
- State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
}
/* Increment/decrement ESI and EDI */
if (OperandSize)
{
- if (State->Flags.Df)
+ if (!State->Flags.Df)
{
State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
}
else
{
- if (State->Flags.Df)
+ if (!State->Flags.Df)
{
State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
}
}
+ // FIXME: This method is slow!
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ BOOLEAN Repeat = TRUE;
+
+ if (OperandSize)
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0)
+ {
+ /* ECX is 0 */
+ Repeat = FALSE;
+ }
+ }
+ else
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0)
+ {
+ /* CX is 0 */
+ Repeat = FALSE;
+ }
+ }
+
+ if (((State->PrefixFlags & SOFT386_PREFIX_REP) && !State->Flags.Zf)
+ || ((State->PrefixFlags & SOFT386_PREFIX_REPNZ) && State->Flags.Zf))
+ {
+ /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
+ Repeat = FALSE;
+ }
+
+ if (Repeat)
+ {
+ /* Repeat the instruction */
+ State->InstPtr = State->SavedInstPtr;
+ }
+ }
+
/* Return success */
return TRUE;
}
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
- /* Write to the destination operand */
- if (!Soft386WriteMemory(State,
- SOFT386_REG_ES,
- AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
- : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
- &State->GeneralRegs[SOFT386_REG_EAX].Long,
- DataSize))
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- /* Exception occurred */
- return FALSE;
- }
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- /* Increment/decrement EDI */
- if (OperandSize)
- {
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
- else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ /* Fill the memory block with the data */
+ if (DataSize == sizeof(UCHAR))
+ {
+ RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[SOFT386_REG_EAX].LowByte);
+ }
+ else
+ {
+ ULONG i;
+
+ for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
+ {
+ if (DataSize == sizeof(USHORT))
+ {
+ ((PUSHORT)Block)[i] = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ }
+ else
+ {
+ ((PULONG)Block)[i] = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ }
+ }
+ }
+
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ if (State->Flags.Df)
+ {
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
- else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
/* Return success */
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
+ {
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
+
+ /* If the count is 0, do nothing */
+ if (Count == 0) return TRUE;
+
+ /* Only the last entry will be loaded */
+ if (!State->Flags.Df)
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long += (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord += (Count - 1) * DataSize;
+ }
+ else
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long -= (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= (Count - 1) * DataSize;
+ }
+ }
+
/* Read from the source operand */
if (!Soft386ReadMemory(State,
SOFT386_REG_DS,
/* Increment/decrement ESI */
if (OperandSize)
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
}
else
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
}
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
- if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
+ if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
/* Calculate the mask and sign flag */
/* Increment/decrement EDI */
if (OperandSize)
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
}
else
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
}
+ // FIXME: This method is slow!
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ BOOLEAN Repeat = TRUE;
+
+ if (OperandSize)
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0)
+ {
+ /* ECX is 0 */
+ Repeat = FALSE;
+ }
+ }
+ else
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0)
+ {
+ /* CX is 0 */
+ Repeat = FALSE;
+ }
+ }
+
+ if (((State->PrefixFlags & SOFT386_PREFIX_REP) && !State->Flags.Zf)
+ || ((State->PrefixFlags & SOFT386_PREFIX_REPNZ) && State->Flags.Zf))
+ {
+ /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
+ Repeat = FALSE;
+ }
+
+ if (Repeat)
+ {
+ /* Repeat the instruction */
+ State->InstPtr = State->SavedInstPtr;
+ }
+ }
+
/* Return success */
return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
{
- ULONG Data = 0;
ULONG DataSize;
BOOLEAN OperandSize, AddressSize;
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
- /* Read from the I/O port */
- State->IoReadCallback(State,
- State->GeneralRegs[SOFT386_REG_EDX].LowWord,
- &Data,
- DataSize);
-
- /* Write to the destination operand */
- if (!Soft386WriteMemory(State,
- SOFT386_REG_ES,
- AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
- : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
- &Data,
- DataSize))
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- /* Exception occurred */
- return FALSE;
- }
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- /* Increment/decrement EDI */
- if (OperandSize)
- {
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
- else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
+
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
+
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
- else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ ULONG Data = 0;
+
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &Data,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
/* Return success */
SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
{
- ULONG Data = 0;
ULONG DataSize;
BOOLEAN OperandSize, AddressSize;
AddressSize = !AddressSize;
}
- if ((State->PrefixFlags & SOFT386_PREFIX_REP)
- || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
- {
- // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Calculate the size */
if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
- /* Read from the source operand */
- if (!Soft386ReadMemory(State,
- SOFT386_REG_DS,
- AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
- : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
- FALSE,
- &Data,
- DataSize))
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- /* Exception occurred */
- return FALSE;
- }
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- /* Write to the I/O port */
- State->IoWriteCallback(State,
- State->GeneralRegs[SOFT386_REG_EDX].LowWord,
- &Data,
- DataSize);
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
- /* Increment/decrement ESI */
- if (OperandSize)
- {
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
- else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ /* Read from memory */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
+
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
+
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
- else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ ULONG Data = 0;
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &Data,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Increment/decrement ESI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ }
}
/* Return success */