[SOFT386]

Fix bugs in STOS and LODS (only one register is incremented).
Implement CMPS and SCAS.


svn path=/branches/ntvdm/; revision=60525
This commit is contained in:
Aleksandar Andrejevic 2013-10-04 19:51:11 +00:00
parent c190ca817c
commit 3593b8c8ef

View file

@ -5700,8 +5700,113 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps) SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
{ {
UNIMPLEMENTED; ULONG FirstValue = 0, SecondValue = 0, Result;
return FALSE; // TODO: NOT IMPLEMENTED ULONG DataSize, DataMask, SignFlag;
BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xFE) == 0xA6);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
OperandSize = !OperandSize;
}
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
/* The ADSIZE prefix toggles the size */
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);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
/* Calculate the mask and sign flag */
DataMask = (1 << (DataSize * 8)) - 1;
SignFlag = 1 << ((DataSize * 8) - 1);
/* Read from the first source operand */
if (!Soft386ReadMemory(State,
SOFT386_REG_DS,
AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
: State->GeneralRegs[SOFT386_REG_ESI].LowWord,
FALSE,
&FirstValue,
DataSize))
{
/* Exception occurred */
return FALSE;
}
/* Read from the second source operand */
if (!Soft386ReadMemory(State,
SOFT386_REG_ES,
AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
: State->GeneralRegs[SOFT386_REG_EDI].LowWord,
FALSE,
&SecondValue,
DataSize))
{
/* Exception occurred */
return FALSE;
}
/* Calculate the result */
FirstValue &= DataMask;
SecondValue &= DataMask;
Result = (FirstValue - SecondValue) & DataMask;
/* Update the flags */
State->Flags.Cf = FirstValue < SecondValue;
State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
&& ((FirstValue & SignFlag) != (Result & SignFlag));
State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
/* 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
{
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;
}
}
/* Return success */
return TRUE;
} }
SOFT386_OPCODE_HANDLER(Soft386OpcodeStos) SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
@ -5750,32 +5855,16 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
return FALSE; return FALSE;
} }
/* Increment/decrement ESI and EDI */ /* Increment/decrement EDI */
if (OperandSize) if (OperandSize)
{ {
if (State->Flags.Df) if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
{ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
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 else
{ {
if (State->Flags.Df) if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
{ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
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;
}
} }
/* Return success */ /* Return success */
@ -5829,32 +5918,16 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
return FALSE; return FALSE;
} }
/* Increment/decrement ESI and EDI */ /* Increment/decrement ESI */
if (OperandSize) if (OperandSize)
{ {
if (State->Flags.Df) if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
{ else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
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 else
{ {
if (State->Flags.Df) if (State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
{ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
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;
}
} }
/* Return success */ /* Return success */
@ -5863,6 +5936,84 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
SOFT386_OPCODE_HANDLER(Soft386OpcodeScas) SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
{ {
UNIMPLEMENTED; ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
return FALSE; // TODO: NOT IMPLEMENTED ULONG SecondValue = 0;
ULONG Result;
ULONG DataSize, DataMask, SignFlag;
BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xFE) == 0xAE);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
OperandSize = !OperandSize;
}
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
/* The ADSIZE prefix toggles the size */
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);
else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
/* Calculate the mask and sign flag */
DataMask = (1 << (DataSize * 8)) - 1;
SignFlag = 1 << ((DataSize * 8) - 1);
/* Read from the source operand */
if (!Soft386ReadMemory(State,
SOFT386_REG_ES,
AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
: State->GeneralRegs[SOFT386_REG_EDI].LowWord,
FALSE,
&SecondValue,
DataSize))
{
/* Exception occurred */
return FALSE;
}
/* Calculate the result */
FirstValue &= DataMask;
SecondValue &= DataMask;
Result = (FirstValue - SecondValue) & DataMask;
/* Update the flags */
State->Flags.Cf = FirstValue < SecondValue;
State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
&& ((FirstValue & SignFlag) != (Result & SignFlag));
State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
/* 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 */
return TRUE;
} }