From 3593b8c8ef75234c66c97eaed60a9684556a5d76 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Fri, 4 Oct 2013 19:51:11 +0000 Subject: [PATCH] [SOFT386] Fix bugs in STOS and LODS (only one register is incremented). Implement CMPS and SCAS. svn path=/branches/ntvdm/; revision=60525 --- lib/soft386/opcodes.c | 229 +++++++++++++++++++++++++++++++++++------- 1 file changed, 190 insertions(+), 39 deletions(-) diff --git a/lib/soft386/opcodes.c b/lib/soft386/opcodes.c index 1563b2880f2..8a6c2336564 100644 --- a/lib/soft386/opcodes.c +++ b/lib/soft386/opcodes.c @@ -5700,19 +5700,14 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs) SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps) { - UNIMPLEMENTED; - return FALSE; // TODO: NOT IMPLEMENTED -} - -SOFT386_OPCODE_HANDLER(Soft386OpcodeStos) -{ - ULONG DataSize; + ULONG FirstValue = 0, SecondValue = 0, 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) == 0xAA); + ASSERT((Opcode & 0xFE) == 0xA6); if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) { @@ -5735,21 +5730,53 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos) } /* Calculate the size */ - if (Opcode == 0xAA) DataSize = sizeof(UCHAR); + if (Opcode == 0xA6) 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)) + /* 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) { @@ -5782,6 +5809,68 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos) return TRUE; } +SOFT386_OPCODE_HANDLER(Soft386OpcodeStos) +{ + ULONG DataSize; + BOOLEAN OperandSize, AddressSize; + + OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + /* Make sure this is the right instruction */ + ASSERT((Opcode & 0xFE) == 0xAA); + + 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 == 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)) + { + /* 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 */ + return TRUE; +} + SOFT386_OPCODE_HANDLER(Soft386OpcodeLods) { ULONG DataSize; @@ -5829,32 +5918,16 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods) return FALSE; } - /* Increment/decrement ESI and EDI */ + /* Increment/decrement ESI */ 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; - } + 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; - State->GeneralRegs[SOFT386_REG_EDI].LowWord += 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; + else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize; } /* Return success */ @@ -5863,6 +5936,84 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods) SOFT386_OPCODE_HANDLER(Soft386OpcodeScas) { - UNIMPLEMENTED; - return FALSE; // TODO: NOT IMPLEMENTED + ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long; + 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; } -- 2.17.1