[SOFT386]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 4 Oct 2013 19:51:11 +0000 (19:51 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 4 Oct 2013 19:51:11 +0000 (19:51 +0000)
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

index 1563b28..8a6c233 100644 (file)
@@ -5700,19 +5700,14 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
 
 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
 {
 
 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 */
     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)
     {
 
     if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
@@ -5735,21 +5730,53 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
     }
 
     /* Calculate the size */
     }
 
     /* Calculate the size */
-    if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
+    if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
     else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
 
     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;
     }
 
     {
         /* 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)
     {
     /* Increment/decrement ESI and EDI */
     if (OperandSize)
     {
@@ -5782,6 +5809,68 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
     return TRUE;
 }
 
     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;
 SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
 {
     ULONG DataSize;
@@ -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)
-        {
-            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
     {
     }
     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 */
     }
 
     /* Return success */
@@ -5863,6 +5936,84 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
 
 SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
 {
 
 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;
 }
 }