[SOFT386]
[reactos.git] / lib / soft386 / opcodes.c
index be33e57..e2dac35 100644 (file)
@@ -466,12 +466,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeIncrement)
     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);
@@ -509,12 +510,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement)
     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);
@@ -549,8 +551,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement)
 
 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);
@@ -569,12 +570,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodePopReg)
     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);
@@ -618,12 +620,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeExchangeEax)
     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);
@@ -974,12 +977,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeIn)
     /* 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);
@@ -1073,12 +1077,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeOut)
     /* 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);
@@ -1152,12 +1157,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm)
     /* 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);
@@ -3084,116 +3090,20 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs)
 }
 
 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))
@@ -3221,40 +3131,32 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
     }
 
     /* 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;
 
@@ -3270,17 +3172,6 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
         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))
     {
@@ -3294,9 +3185,9 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
         ULONG FirstValue, SecondValue, Result;
 
         if (!Soft386ReadModrmDwordOperands(State,
-                                          &ModRegRm,
-                                          &FirstValue,
-                                          &SecondValue))
+                                           &ModRegRm,
+                                           &FirstValue,
+                                           &SecondValue))
         {
             /* Exception occurred */
             return FALSE;
@@ -3312,31 +3203,22 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
         }
     
         /* 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
     {
@@ -3361,42 +3243,33 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
         }
     
         /* 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)
     {
@@ -3412,33 +3285,31 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
     }
 
     /* 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)
     {
@@ -3465,23 +3336,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
         }
 
         /* 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
     {
@@ -3495,13 +3362,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
         }
 
         /* 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);
@@ -3511,22 +3378,424 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
     }
 
     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;
@@ -3616,12 +3885,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
     /* 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);
@@ -3664,12 +3934,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
     /* 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);
@@ -4267,12 +4538,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde)
     /* 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);
@@ -4307,12 +4579,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
     /* 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);
@@ -4559,7 +4832,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
         return FALSE;
     }
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
         /* The OPSIZE prefix toggles the size */
         Size = !Size;
@@ -5173,10 +5446,34 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
 
 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)
@@ -5248,7 +5545,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
         return FALSE;
     }
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
         /* The OPSIZE prefix toggles the size */
         Size = !Size;
@@ -5280,12 +5577,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCall)
     /* 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);
@@ -5345,12 +5643,13 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
     /* 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);
@@ -5391,10 +5690,63 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
 
 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)
@@ -5630,68 +5982,163 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
         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;
+            }
         }
     }
 
@@ -5781,7 +6228,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
     /* 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;
@@ -5794,7 +6241,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
     }
     else
     {
-        if (State->Flags.Df)
+        if (!State->Flags.Df)
         {
             State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
             State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
@@ -5806,6 +6253,43 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
         }
     }
 
+    // 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;
 }
@@ -5832,40 +6316,117 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
         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 */
@@ -5894,18 +6455,31 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
         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,
@@ -5922,12 +6496,12 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
     /* 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;
     }
 
@@ -5960,16 +6534,8 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
         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 */
@@ -6006,22 +6572,58 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
     /* 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;
 
@@ -6042,46 +6644,126 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
         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 */
@@ -6090,7 +6772,6 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
 
 SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
 {
-    ULONG Data = 0;
     ULONG DataSize;
     BOOLEAN OperandSize, AddressSize;
 
@@ -6111,47 +6792,128 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
         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 */