[SOFT386]
[reactos.git] / lib / soft386 / opcodes.c
index 7e139f0..c0907cc 100644 (file)
@@ -1,9 +1,22 @@
 /*
- * COPYRIGHT:       GPL - See COPYING in the top level directory
- * PROJECT:         386/486 CPU Emulation Library
- * FILE:            opcodes.c
- * PURPOSE:         Opcode handlers.
- * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Soft386 386/486 CPU Emulation Library
+ * opcodes.c
+ *
+ * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 /* INCLUDES *******************************************************************/
 // #define WIN32_NO_STATUS
 // #define _INC_WINDOWS
 #include <windef.h>
+#include <limits.h>
 
 // #define NDEBUG
 #include <debug.h>
 
 #include <soft386.h>
 #include "opcodes.h"
+#include "opgroups.h"
+#include "extraops.h"
 #include "common.h"
 
 /* PUBLIC VARIABLES ***********************************************************/
@@ -39,7 +55,7 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodeOrAl,
     Soft386OpcodeOrEax,
     Soft386OpcodePushCs,
-    NULL, // TODO: OPCODE 0x0F NOT SUPPORTED
+    Soft386OpcodeExtended,
     Soft386OpcodeAdcByteModrm,
     Soft386OpcodeAdcModrm,
     Soft386OpcodeAdcByteModrm,
@@ -131,11 +147,11 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodePushImm,
     Soft386OpcodeImulModrmImm,
     Soft386OpcodePushByteImm,
-    Soft386OpcodeImulModrmByteImm,
-    NULL, // TODO: OPCODE 0x6C NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x6D NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x6E NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x6F NOT SUPPORTED
+    Soft386OpcodeImulModrmImm,
+    Soft386OpcodeIns,
+    Soft386OpcodeIns,
+    Soft386OpcodeOuts,
+    Soft386OpcodeOuts,
     Soft386OpcodeShortConditionalJmp,
     Soft386OpcodeShortConditionalJmp,
     Soft386OpcodeShortConditionalJmp,
@@ -152,10 +168,10 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodeShortConditionalJmp,
     Soft386OpcodeShortConditionalJmp,
     Soft386OpcodeShortConditionalJmp,
-    NULL, // TODO: OPCODE 0x80 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x81 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x82 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0x83 NOT SUPPORTED
+    Soft386OpcodeGroup8082,
+    Soft386OpcodeGroup81,
+    Soft386OpcodeGroup8082,
+    Soft386OpcodeGroup83,
     Soft386OpcodeTestByteModrm,
     Soft386OpcodeTestModrm,
     Soft386OpcodeXchgByteModrm,
@@ -167,7 +183,7 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodeMovStoreSeg,
     Soft386OpcodeLea,
     Soft386OpcodeMovLoadSeg,
-    NULL, // TODO: OPCODE 0x8F NOT SUPPORTED
+    Soft386OpcodeGroup8F,
     Soft386OpcodeNop,
     Soft386OpcodeExchangeEax,
     Soft386OpcodeExchangeEax,
@@ -184,22 +200,22 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodePopFlags,
     Soft386OpcodeSahf,
     Soft386OpcodeLahf,
-    NULL, // TODO: OPCODE 0xA0 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA1 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA2 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA3 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA4 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA5 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA6 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xA7 NOT SUPPORTED
+    Soft386OpcodeMovAlOffset,
+    Soft386OpcodeMovEaxOffset,
+    Soft386OpcodeMovOffsetAl,
+    Soft386OpcodeMovOffsetEax,
+    Soft386OpcodeMovs,
+    Soft386OpcodeMovs,
+    Soft386OpcodeCmps,
+    Soft386OpcodeCmps,
     Soft386OpcodeTestAl,
     Soft386OpcodeTestEax,
-    NULL, // TODO: OPCODE 0xAA NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xAB NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xAC NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xAD NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xAE NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xAF NOT SUPPORTED
+    Soft386OpcodeStos,
+    Soft386OpcodeStos,
+    Soft386OpcodeLods,
+    Soft386OpcodeLods,
+    Soft386OpcodeScas,
+    Soft386OpcodeScas,
     Soft386OpcodeMovByteRegImm,
     Soft386OpcodeMovByteRegImm,
     Soft386OpcodeMovByteRegImm,
@@ -216,29 +232,29 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodeMovRegImm,
     Soft386OpcodeMovRegImm,
     Soft386OpcodeMovRegImm,
-    NULL, // TODO: OPCODE 0xC0 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xC1 NOT SUPPORTED
-    Soft386OpcodeRetImm,
+    Soft386OpcodeGroupC0,
+    Soft386OpcodeGroupC1,
+    Soft386OpcodeRet,
     Soft386OpcodeRet,
-    Soft386OpcodeLes,
-    Soft386OpcodeLds,
-    NULL, // TODO: OPCODE 0xC6 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xC7 NOT SUPPORTED
+    Soft386OpcodeLdsLes,
+    Soft386OpcodeLdsLes,
+    Soft386OpcodeGroupC6,
+    Soft386OpcodeGroupC7,
     Soft386OpcodeEnter,
     Soft386OpcodeLeave,
     Soft386OpcodeRetFarImm,
     Soft386OpcodeRetFar,
-    Soft386OpcodeInt3,
     Soft386OpcodeInt,
-    Soft386OpcodeIntOverflow,
+    Soft386OpcodeInt,
+    Soft386OpcodeInt,
     Soft386OpcodeIret,
-    NULL, // TODO: OPCODE 0xD0 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xD1 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xD2 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xD3 NOT SUPPORTED
+    Soft386OpcodeGroupD0,
+    Soft386OpcodeGroupD1,
+    Soft386OpcodeGroupD2,
+    Soft386OpcodeGroupD3,
     Soft386OpcodeAam,
     Soft386OpcodeAad,
-    NULL, // TODO: OPCODE 0xD6 NOT SUPPORTED
+    Soft386OpcodeSalc,
     Soft386OpcodeXlat,
     NULL, // TODO: OPCODE 0xD8 NOT SUPPORTED
     NULL, // TODO: OPCODE 0xD9 NOT SUPPORTED
@@ -270,16 +286,16 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
     Soft386OpcodePrefix,
     Soft386OpcodeHalt,
     Soft386OpcodeComplCarry,
-    NULL, // TODO: OPCODE 0xF6 NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xF7 NOT SUPPORTED
+    Soft386OpcodeGroupF6,
+    Soft386OpcodeGroupF7,
     Soft386OpcodeClearCarry,
     Soft386OpcodeSetCarry,
     Soft386OpcodeClearInt,
     Soft386OpcodeSetInt,
     Soft386OpcodeClearDir,
     Soft386OpcodeSetDir,
-    NULL, // TODO: OPCODE 0xFE NOT SUPPORTED
-    NULL, // TODO: OPCODE 0xFF NOT SUPPORTED
+    Soft386OpcodeGroupFE,
+    Soft386OpcodeGroupFF,
 };
 
 /* PUBLIC FUNCTIONS ***********************************************************/
@@ -450,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);
@@ -493,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);
@@ -533,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);
@@ -553,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);
@@ -602,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);
@@ -958,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);
@@ -1057,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);
@@ -1136,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);
@@ -1425,18 +1447,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x05);
 
-    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);
         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;
@@ -1695,18 +1718,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x0D);
 
-    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);
         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;
@@ -1925,9 +1949,9 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x24);
 
-    if (State->PrefixFlags)
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
     {
-        /* This opcode doesn't take any prefixes */
+        /* Invalid prefix */
         Soft386Exception(State, SOFT386_EXCEPTION_UD);
         return FALSE;
     }
@@ -1961,18 +1985,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x25);
 
-    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);
         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;
@@ -2227,18 +2252,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x35);
 
-    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);
         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;
@@ -2478,18 +2504,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0xA9);
 
-    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);
         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;
@@ -2965,18 +2992,19 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax)
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x15);
 
-    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);
         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;
@@ -3062,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))
@@ -3199,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;
 
@@ -3248,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))
     {
@@ -3272,9 +3185,9 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
         ULONG FirstValue, SecondValue, Result;
 
         if (!Soft386ReadModrmDwordOperands(State,
-                                          &ModRegRm,
-                                          &FirstValue,
-                                          &SecondValue))
+                                           &ModRegRm,
+                                           &FirstValue,
+                                           &SecondValue))
         {
             /* Exception occurred */
             return FALSE;
@@ -3290,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
     {
@@ -3339,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)
     {
@@ -3390,46 +3285,45 @@ 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_OPSIZE)
-    {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
-    }
-    else
+    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;
@@ -3442,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
     {
@@ -3472,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);
@@ -3488,9 +3378,30 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
     }
 
     return TRUE;
+
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
+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;
@@ -3498,14 +3409,14 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
     /* Clear the carry flag */
     State->Flags.Cf = FALSE;
 
-    /* Check if the first BCD digit is invalid or there was a borrow */
+    /* 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 > 0xFB)
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
+        if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
         {
-            /* A borrow occurred */
+            /* A carry occurred */
             State->Flags.Cf = TRUE;
         }
 
@@ -3513,453 +3424,551 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
         State->Flags.Af = TRUE;
     }
 
-    /* Check if the second BCD digit is invalid or there was a borrow */
+    /* 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;
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
 
-        /* There was a borrow */
+        /* There was a carry */
         State->Flags.Cf = TRUE;
     }
 
     return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
 {
-    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+    UCHAR FirstValue, SecondValue, Result;
+    SOFT386_MOD_REG_RM ModRegRm;
+    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
-    /*
-     * Check if the value in AL is not a valid BCD digit,
-     * or there was a carry from the lowest 4 bits of AL
-     */
-    if (((Value & 0x0F) > 9) || State->Flags.Af)
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xED) == 0x28);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* Correct it */
-        State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
-        State->GeneralRegs[SOFT386_REG_EAX].HighByte++;
+        /* 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;
+    }
 
-        /* Set CF and AF */
-        State->Flags.Cf = State->Flags.Af = TRUE;
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
     }
-    else
+
+    if (!Soft386ReadModrmByteOperands(State,
+                                      &ModRegRm,
+                                      &FirstValue,
+                                      &SecondValue))
     {
-        /* Clear CF and AF */
-        State->Flags.Cf = State->Flags.Af = FALSE;
+        /* Exception occurred */
+        return FALSE;
     }
 
-    /* Keep only the lowest 4 bits of AL */
-    State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
+    /* 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;
+    }
 
-    return TRUE;
-}
+    /* Calculate the result */
+    Result = FirstValue - SecondValue;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAas)
-{
-    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+    /* 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 the value in AL is not a valid BCD digit,
-     * or there was a borrow from the lowest 4 bits of AL
-     */
-    if (((Value & 0x0F) > 9) || State->Flags.Af)
+    /* Check if this is not a CMP */
+    if (!(Opcode & 0x10))
     {
-        /* Correct it */
-        State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
-        State->GeneralRegs[SOFT386_REG_EAX].HighByte--;
-
-        /* Set CF and AF */
-        State->Flags.Cf = State->Flags.Af = TRUE;
+        /* Write back the result */
+        return Soft386WriteModrmByteOperands(State,
+                                             &ModRegRm,
+                                             Opcode & SOFT386_OPCODE_WRITE_REG,
+                                             Result);
     }
     else
     {
-        /* Clear CF and AF */
-        State->Flags.Cf = State->Flags.Af = FALSE;
+        /* Discard the result */
+        return TRUE;
     }
-
-    /* Keep only the lowest 4 bits of AL */
-    State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
-
-    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
 {
-    INT i;
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-    SOFT386_REG SavedEsp = State->GeneralRegs[SOFT386_REG_ESP];
+    SOFT386_MOD_REG_RM ModRegRm;
+    BOOLEAN OperandSize, AddressSize;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x60);
+    ASSERT((Opcode & 0xED) == 0x29);
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
+        /* The ADSIZE prefix toggles the address size */
+        AddressSize = !AddressSize;
     }
-    else
+
+    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;
     }
 
-    /* Push all the registers in order */
-    for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
     {
-        if (i == SOFT386_REG_ESP)
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Check the operand size */
+    if (OperandSize)
+    {
+        ULONG FirstValue, SecondValue, Result;
+
+        if (!Soft386ReadModrmDwordOperands(State,
+                                          &ModRegRm,
+                                          &FirstValue,
+                                          &SecondValue))
         {
-            /* Use the saved ESP instead */
-            if (!Soft386StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
-            {
-                /* Exception occurred */
-                return FALSE;
-            }
+            /* Exception occurred */
+            return FALSE;
         }
-        else
+
+        /* Check if this is the instruction that writes to R/M */
+        if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
         {
-            /* Push the register */
-            if (!Soft386StackPush(State, Size ? State->GeneralRegs[i].Long
-                                              : State->GeneralRegs[i].LowWord))
-            {
-                /* Exception occurred */
-                return FALSE;
-            }
+            /* Swap the order */
+            FirstValue ^= SecondValue;
+            SecondValue ^= FirstValue;
+            FirstValue ^= SecondValue;
         }
-    }
-
-    return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
-{
-    INT i;
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-    ULONG Value;
+    
+        /* Calculate the result */
+        Result = FirstValue - SecondValue;
 
-    /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x61);
+        /* 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);
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
-    {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
+        /* 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
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
-    }
+        USHORT FirstValue, SecondValue, Result;
 
-    /* Pop all the registers in reverse order */
-    for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
-    {
-        /* Pop the value */
-        if (!Soft386StackPop(State, &Value))
+        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;
 
-        /* Don't modify ESP */
-        if (i != SOFT386_REG_ESP)
+        /* 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))
         {
-            if (Size) State->GeneralRegs[i].Long = Value;
-            else State->GeneralRegs[i].LowWord = LOWORD(Value);
+            /* Write back the result */
+            return Soft386WriteModrmWordOperands(State,
+                                                 &ModRegRm,
+                                                 Opcode & SOFT386_OPCODE_WRITE_REG,
+                                                 Result);
+        }
+        else
+        {
+            /* Discard the result */
+            return TRUE;
         }
     }
-
-    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
-
-    return FALSE;
-}
+    UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+    UCHAR SecondValue, Result;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
-{
-    USHORT FirstValue, SecondValue;
-    SOFT386_MOD_REG_RM ModRegRm;
-    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xEF) == 0x2C);
 
-    if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
-        || State->Flags.Vm
-        || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
+    if (State->PrefixFlags)
     {
-        /* Cannot be used in real mode or with a LOCK prefix */
+        /* This opcode doesn't take any prefixes */
         Soft386Exception(State, SOFT386_EXCEPTION_UD);
         return FALSE;
     }
 
-    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
-    {
-        /* The ADSIZE prefix toggles the size */
-        AddressSize = !AddressSize;
-    }
-
-    /* Get the operands */
-    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
-    {
-        /* Exception occurred */
-        return FALSE;
-    }
-
-    /* Read the operands */
-    if (!Soft386ReadModrmWordOperands(State,
-                                      &ModRegRm,
-                                      &FirstValue,
-                                      &SecondValue))
+    if (!Soft386FetchByte(State, &SecondValue))
     {
         /* Exception occurred */
         return FALSE;
     }
 
-    /* Check if the RPL needs adjusting */
-    if ((SecondValue & 3) < (FirstValue & 3))
-    {
-        /* Adjust the RPL */
-        SecondValue &= ~3;
-        SecondValue |= FirstValue & 3;
+    /* Calculate the result */
+    Result = FirstValue - SecondValue;
 
-        /* Set ZF */
-        State->Flags.Zf = TRUE;
+    /* 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);
 
-        /* Write back the result */
-        return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
-    }
-    else
+    /* Check if this is not a CMP */
+    if (!(Opcode & 0x10))
     {
-        /* Clear ZF */
-        State->Flags.Zf = FALSE;
-        return TRUE;
+        /* Write back the result */
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
     }
+
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
 {
     BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x68);
+    ASSERT((Opcode & 0xEF) == 0x2D);
 
-    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);
         return FALSE;
     }
 
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
     if (Size)
     {
-        ULONG Data;
+        ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+        ULONG SecondValue, Result;
 
-        if (!Soft386FetchDword(State, &Data))
+        if (!Soft386FetchDword(State, &SecondValue))
         {
             /* Exception occurred */
             return FALSE;
         }
 
-        /* Call the internal API */
-        return Soft386StackPush(State, Data);
+        /* 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 Data;
+        USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+        USHORT SecondValue, Result;
 
-        if (!Soft386FetchWord(State, &Data))
+        if (!Soft386FetchWord(State, &SecondValue))
         {
             /* Exception occurred */
             return FALSE;
         }
 
-        /* Call the internal API */
-        return Soft386StackPush(State, Data);
+        /* 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(Soft386OpcodeImulModrmImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+    BOOLEAN Carry = State->Flags.Cf;
 
-    return FALSE;
+    /* 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;
+        }
+
+        /* Set the adjust flag */
+        State->Flags.Af = TRUE;
+    }
+
+    /* Check if the second BCD digit is invalid or there was a borrow */
+    if ((Value > 0x99) || Carry)
+    {
+        /* Correct it */
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x60;
+
+        /* There was a borrow */
+        State->Flags.Cf = TRUE;
+    }
+
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa)
 {
-    UCHAR Data;
+    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
 
-    /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x6A);
+    /*
+     * Check if the value in AL is not a valid BCD digit,
+     * or there was a carry from the lowest 4 bits of AL
+     */
+    if (((Value & 0x0F) > 9) || State->Flags.Af)
+    {
+        /* Correct it */
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
+        State->GeneralRegs[SOFT386_REG_EAX].HighByte++;
 
-    if (!Soft386FetchByte(State, &Data))
+        /* Set CF and AF */
+        State->Flags.Cf = State->Flags.Af = TRUE;
+    }
+    else
     {
-        /* Exception occurred */
-        return FALSE;
+        /* Clear CF and AF */
+        State->Flags.Cf = State->Flags.Af = FALSE;
     }
 
-    /* Call the internal API */
-    return Soft386StackPush(State, Data);
+    /* Keep only the lowest 4 bits of AL */
+    State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
+
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmByteImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAas)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
 
-    return FALSE;
+    /*
+     * Check if the value in AL is not a valid BCD digit,
+     * or there was a borrow from the lowest 4 bits of AL
+     */
+    if (((Value & 0x0F) > 9) || State->Flags.Af)
+    {
+        /* Correct it */
+        State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
+        State->GeneralRegs[SOFT386_REG_EAX].HighByte--;
+
+        /* Set CF and AF */
+        State->Flags.Cf = State->Flags.Af = TRUE;
+    }
+    else
+    {
+        /* Clear CF and AF */
+        State->Flags.Cf = State->Flags.Af = FALSE;
+    }
+
+    /* Keep only the lowest 4 bits of AL */
+    State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
+
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
 {
-    UCHAR FirstValue, SecondValue, Result;
-    SOFT386_MOD_REG_RM ModRegRm;
-    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+    INT i;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    SOFT386_REG SavedEsp = State->GeneralRegs[SOFT386_REG_ESP];
 
     /* Make sure this is the right instruction */
-    ASSERT((Opcode & 0xFD) == 0x88);
+    ASSERT(Opcode == 0x60);
 
-    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* The ADSIZE prefix toggles the size */
-        AddressSize = !AddressSize;
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
     }
-    else if (State->PrefixFlags
-             & ~(SOFT386_PREFIX_ADSIZE
-             | SOFT386_PREFIX_SEG
-             | SOFT386_PREFIX_LOCK))
+
+    if (State->PrefixFlags & 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))
+    /* Push all the registers in order */
+    for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
     {
-        /* Exception occurred */
-        return FALSE;
+        if (i == SOFT386_REG_ESP)
+        {
+            /* Use the saved ESP instead */
+            if (!Soft386StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
+        else
+        {
+            /* Push the register */
+            if (!Soft386StackPush(State, Size ? State->GeneralRegs[i].Long
+                                              : State->GeneralRegs[i].LowWord))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
     }
 
-    if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
-    else Result = FirstValue;
-
-    /* Write back the result */
-    return Soft386WriteModrmByteOperands(State,
-                                         &ModRegRm,
-                                         Opcode & SOFT386_OPCODE_WRITE_REG,
-                                         Result);
-
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
 {
-    SOFT386_MOD_REG_RM ModRegRm;
-    BOOLEAN OperandSize, AddressSize;
+    INT i;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    ULONG Value;
 
     /* Make sure this is the right instruction */
-    ASSERT((Opcode & 0xFD) == 0x89);
-
-    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
-
-    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
-    {
-        /* The ADSIZE prefix toggles the address size */
-        AddressSize = !AddressSize;
-    }
+    ASSERT(Opcode == 0x61);
 
     if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* The OPSIZE prefix toggles the operand size */
-        OperandSize = !OperandSize;
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
     }
 
-    if (State->PrefixFlags
-             & ~(SOFT386_PREFIX_ADSIZE
-             | SOFT386_PREFIX_OPSIZE
-             | SOFT386_PREFIX_SEG
-             | SOFT386_PREFIX_LOCK))
+    if (State->PrefixFlags & 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)
+    /* Pop all the registers in reverse order */
+    for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
     {
-        ULONG FirstValue, SecondValue, Result;
-
-        if (!Soft386ReadModrmDwordOperands(State,
-                                          &ModRegRm,
-                                          &FirstValue,
-                                          &SecondValue))
+        /* Pop the value */
+        if (!Soft386StackPop(State, &Value))
         {
             /* Exception occurred */
             return FALSE;
         }
 
-        if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
-        else Result = FirstValue;
-    
-        /* Write back the result */
-        return Soft386WriteModrmDwordOperands(State,
-                                              &ModRegRm,
-                                              Opcode & SOFT386_OPCODE_WRITE_REG,
-                                              Result);
-    }
-    else
-    {
-        USHORT FirstValue, SecondValue, Result;
-
-        if (!Soft386ReadModrmWordOperands(State,
-                                          &ModRegRm,
-                                          &FirstValue,
-                                          &SecondValue))
+        /* Don't modify ESP */
+        if (i != SOFT386_REG_ESP)
         {
-            /* Exception occurred */
-            return FALSE;
+            if (Size) State->GeneralRegs[i].Long = Value;
+            else State->GeneralRegs[i].LowWord = LOWORD(Value);
         }
-    
-        if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
-        else Result = FirstValue;
-
-        /* Write back the result */
-        return Soft386WriteModrmWordOperands(State,
-                                             &ModRegRm,
-                                             Opcode & SOFT386_OPCODE_WRITE_REG,
-                                             Result);
     }
+
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
 {
     // TODO: NOT IMPLEMENTED
     UNIMPLEMENTED;
@@ -3967,26 +3976,25 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
     return FALSE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
 {
+    USHORT FirstValue, SecondValue;
     SOFT386_MOD_REG_RM ModRegRm;
-    BOOLEAN OperandSize, AddressSize;
-
-    /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x8D);
-
-    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
-    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+    if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+        || State->Flags.Vm
+        || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
     {
-        /* The ADSIZE prefix toggles the address size */
-        AddressSize = !AddressSize;
+        /* Cannot be used in real mode or with a LOCK prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
     }
 
-    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* The OPSIZE prefix toggles the operand size */
-        OperandSize = !OperandSize;
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
     }
 
     /* Get the operands */
@@ -3996,231 +4004,1848 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
         return FALSE;
     }
 
-    /* The second operand must be memory */
-    if (!ModRegRm.Memory)
+    /* Read the operands */
+    if (!Soft386ReadModrmWordOperands(State,
+                                      &ModRegRm,
+                                      &FirstValue,
+                                      &SecondValue))
     {
-        /* Invalid */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        /* Exception occurred */
         return FALSE;
     }
 
-    /* Write the address to the register */
-    if (OperandSize)
+    /* Check if the RPL needs adjusting */
+    if ((SecondValue & 3) < (FirstValue & 3))
     {
-        return Soft386WriteModrmDwordOperands(State,
-                                              &ModRegRm,
-                                              TRUE,
-                                              ModRegRm.MemoryAddress);
+        /* Adjust the RPL */
+        SecondValue &= ~3;
+        SecondValue |= FirstValue & 3;
+
+        /* Set ZF */
+        State->Flags.Zf = TRUE;
+
+        /* Write back the result */
+        return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
     }
     else
     {
-        return Soft386WriteModrmWordOperands(State,
-                                             &ModRegRm,
-                                             TRUE,
-                                             ModRegRm.MemoryAddress);
-
+        /* Clear ZF */
+        State->Flags.Zf = FALSE;
+        return TRUE;
     }
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
-
-    return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
 {
     BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x98);
+    ASSERT(Opcode == 0x68);
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
-    {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
-    }
-    else if (State->PrefixFlags != 0)
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
     {
         /* Invalid prefix */
         Soft386Exception(State, SOFT386_EXCEPTION_UD);
         return FALSE;
     }
 
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
     if (Size)
     {
-        /* Sign extend AX to EAX */
-        State->GeneralRegs[SOFT386_REG_EAX].Long = MAKELONG
-        (
-            State->GeneralRegs[SOFT386_REG_EAX].LowWord,
-            (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
-            ? 0xFFFF : 0x0000
-        );
+        ULONG Data;
+
+        if (!Soft386FetchDword(State, &Data))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Call the internal API */
+        return Soft386StackPush(State, Data);
     }
     else
     {
-        /* Sign extend AL to AX */
-        State->GeneralRegs[SOFT386_REG_EAX].HighByte =
-        (State->GeneralRegs[SOFT386_REG_EAX].LowByte & SIGN_FLAG_BYTE)
-        ? 0xFF : 0x00;
-    }
+        USHORT Data;
 
-    return TRUE;
+        if (!Soft386FetchWord(State, &Data))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Call the internal API */
+        return Soft386StackPush(State, Data);
+    }
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
 {
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    BOOLEAN OperandSize, AddressSize;
+    SOFT386_MOD_REG_RM ModRegRm;
+    LONG Multiplier;
+    LONGLONG Product;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x99);
+    ASSERT((Opcode & 0xFD) == 0x69);
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
-    {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
-    }
-    else if (State->PrefixFlags != 0)
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        /* The ADSIZE prefix toggles the address size */
+        AddressSize = !AddressSize;
     }
 
-    if (Size)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* Sign extend EAX to EDX:EAX */
-        State->GeneralRegs[SOFT386_REG_EDX].Long =
-        (State->GeneralRegs[SOFT386_REG_EAX].Long & SIGN_FLAG_LONG)
-        ? 0xFFFFFFFF : 0x00000000;
+        /* The OPSIZE prefix toggles the operand size */
+        OperandSize = !OperandSize;
     }
-    else
+
+    /* Fetch the parameters */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
     {
-        /* Sign extend AX to DX:AX */
-        State->GeneralRegs[SOFT386_REG_EDX].LowWord =
-        (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
-        ? 0xFFFF : 0x0000;
+        /* Exception occurred */
+        return FALSE;
     }
 
-    return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
-
-    return FALSE;
-}
+    if (Opcode == 0x6B)
+    {
+        CHAR Byte;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeWait)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+        /* Fetch the immediate operand */
+        if (!Soft386FetchByte(State, (PUCHAR)&Byte))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
 
-    return FALSE;
-}
+        Multiplier = (LONG)Byte;
+    }
+    else
+    {
+        if (OperandSize)
+        {
+            LONG Dword;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+            /* Fetch the immediate operand */
+            if (!Soft386FetchDword(State, (PULONG)&Dword))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
 
-    return FALSE;
-}
+            Multiplier = Dword;
+        }
+        else
+        {
+            SHORT Word;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+            /* Fetch the immediate operand */
+            if (!Soft386FetchWord(State, (PUSHORT)&Word))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
 
-    return FALSE;
-}
+            Multiplier = (LONG)Word;
+        }
+    }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf)
-{
-    /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x9E);
+    if (OperandSize)
+    {
+        LONG RegValue, Multiplicand;
 
-    /* Set the low-order byte of FLAGS to AH */
-    State->Flags.Long &= 0xFFFFFF00;
-    State->Flags.Long |= State->GeneralRegs[SOFT386_REG_EAX].HighByte;
+        /* Read the operands */
+        if (!Soft386ReadModrmDwordOperands(State,
+                                           &ModRegRm,
+                                           (PULONG)&RegValue,
+                                           (PULONG)&Multiplicand))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
 
-    /* Restore the reserved bits of FLAGS */
-    State->Flags.AlwaysSet = TRUE;
-    State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
+        /* Multiply */
+        Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+    }
+    else
+    {
+        SHORT RegValue, Multiplicand;
 
-    return FALSE;
-}
+        /* Read the operands */
+        if (!Soft386ReadModrmWordOperands(State,
+                                          &ModRegRm,
+                                          (PUSHORT)&RegValue,
+                                          (PUSHORT)&Multiplicand))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
-{
-    /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0x9F);
+        /* Multiply */
+        Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+    }
 
-    /* Set AH to the low-order byte of FLAGS */
-    State->GeneralRegs[SOFT386_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
+    /* Check for carry/overflow */
+    if ((Product < LONG_MIN) || (Product > LONG_MAX))
+    {
+        State->Flags.Cf = State->Flags.Of = TRUE;
+    }
+    else State->Flags.Cf = State->Flags.Of = FALSE;
 
-    return FALSE;
+    /* Write-back the result */
+    return Soft386WriteModrmDwordOperands(State,
+                                          &ModRegRm,
+                                          TRUE,
+                                          (ULONG)((LONG)Product));
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRetImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    UCHAR Data;
 
-    return FALSE;
-}
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x6A);
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    if (!Soft386FetchByte(State, &Data))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
 
-    return FALSE;
+    /* Call the internal API */
+    return Soft386StackPush(State, Data);
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLes)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    UCHAR FirstValue, SecondValue, Result;
+    SOFT386_MOD_REG_RM ModRegRm;
+    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
-    return FALSE;
-}
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xFD) == 0x88);
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLds)
+    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;
+    }
+
+    if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+    else Result = FirstValue;
+
+    /* Write back the result */
+    return Soft386WriteModrmByteOperands(State,
+                                         &ModRegRm,
+                                         Opcode & SOFT386_OPCODE_WRITE_REG,
+                                         Result);
+
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm)
+{
+    SOFT386_MOD_REG_RM ModRegRm;
+    BOOLEAN OperandSize, AddressSize;
+
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xFD) == 0x89);
+
+    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;
+        }
+
+        if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+        else Result = FirstValue;
+    
+        /* Write back the result */
+        return Soft386WriteModrmDwordOperands(State,
+                                              &ModRegRm,
+                                              Opcode & SOFT386_OPCODE_WRITE_REG,
+                                              Result);
+    }
+    else
+    {
+        USHORT FirstValue, SecondValue, Result;
+
+        if (!Soft386ReadModrmWordOperands(State,
+                                          &ModRegRm,
+                                          &FirstValue,
+                                          &SecondValue))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+    
+        if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+        else Result = FirstValue;
+
+        /* Write back the result */
+        return Soft386WriteModrmWordOperands(State,
+                                             &ModRegRm,
+                                             Opcode & SOFT386_OPCODE_WRITE_REG,
+                                             Result);
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
+{
+    BOOLEAN OperandSize, AddressSize;
+    SOFT386_MOD_REG_RM ModRegRm;
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x8C);
+
+    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;
+    }
+
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
+    {
+        /* Invalid */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    if (OperandSize)
+    {
+        return Soft386WriteModrmDwordOperands(State,
+                                              &ModRegRm,
+                                              FALSE,
+                                              State->SegmentRegs[ModRegRm.Register].Selector);
+    }
+    else
+    {
+        return Soft386WriteModrmWordOperands(State,
+                                             &ModRegRm,
+                                             FALSE,
+                                             State->SegmentRegs[ModRegRm.Register].Selector);
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
+{
+    SOFT386_MOD_REG_RM ModRegRm;
+    BOOLEAN OperandSize, AddressSize;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x8D);
+
+    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;
+    }
+
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* The second operand must be memory */
+    if (!ModRegRm.Memory)
+    {
+        /* Invalid */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    /* Write the address to the register */
+    if (OperandSize)
+    {
+        return Soft386WriteModrmDwordOperands(State,
+                                              &ModRegRm,
+                                              TRUE,
+                                              ModRegRm.MemoryAddress);
+    }
+    else
+    {
+        return Soft386WriteModrmWordOperands(State,
+                                             &ModRegRm,
+                                             TRUE,
+                                             ModRegRm.MemoryAddress);
+
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg)
+{
+    BOOLEAN OperandSize, AddressSize;
+    SOFT386_MOD_REG_RM ModRegRm;
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x8E);
+
+    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;
+    }
+
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if ((ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
+        || ((SOFT386_SEG_REGS)ModRegRm.Register == SOFT386_REG_CS))
+    {
+        /* Invalid */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    if (OperandSize)
+    {
+        ULONG Dummy, Selector;
+
+        if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Selector))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        return Soft386LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
+    }
+    else
+    {
+        USHORT Dummy, Selector;
+
+        if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Selector))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        return Soft386LoadSegment(State, ModRegRm.Register, Selector);
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x98);
+
+    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;
+    }
+
+    if (Size)
+    {
+        /* Sign extend AX to EAX */
+        State->GeneralRegs[SOFT386_REG_EAX].Long = MAKELONG
+        (
+            State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+            (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
+            ? 0xFFFF : 0x0000
+        );
+    }
+    else
+    {
+        /* Sign extend AL to AX */
+        State->GeneralRegs[SOFT386_REG_EAX].HighByte =
+        (State->GeneralRegs[SOFT386_REG_EAX].LowByte & SIGN_FLAG_BYTE)
+        ? 0xFF : 0x00;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x99);
+
+    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;
+    }
+
+    if (Size)
+    {
+        /* Sign extend EAX to EDX:EAX */
+        State->GeneralRegs[SOFT386_REG_EDX].Long =
+        (State->GeneralRegs[SOFT386_REG_EAX].Long & SIGN_FLAG_LONG)
+        ? 0xFFFFFFFF : 0x00000000;
+    }
+    else
+    {
+        /* Sign extend AX to DX:AX */
+        State->GeneralRegs[SOFT386_REG_EDX].LowWord =
+        (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
+        ? 0xFFFF : 0x0000;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs)
+{
+    // TODO: NOT IMPLEMENTED
+    UNIMPLEMENTED;
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeWait)
+{
+    // TODO: NOT IMPLEMENTED
+    UNIMPLEMENTED;
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    {
+        /* Invalid prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* This OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
+    /* Check for VM86 mode when IOPL is not 3 */
+    if (State->Flags.Vm && (State->Flags.Iopl != 3))
+    {
+        /* Call the VM86 monitor */
+        Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+        return FALSE;
+    }
+
+    /* Push the flags */
+    if (Size) return Soft386StackPush(State, State->Flags.Long);
+    else return Soft386StackPush(State, LOWORD(State->Flags.Long));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    INT Cpl = Soft386GetCurrentPrivLevel(State);
+    ULONG NewFlags;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    {
+        /* Invalid prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* This OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
+    /* Pop the new flags */
+    if (!Soft386StackPop(State, &NewFlags))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (!State->Flags.Vm)
+    {
+        /* Check the current privilege level */
+        if (Cpl == 0)
+        {
+            /* Supervisor */
+
+            /* Set the flags */
+            if (Size)
+            {
+                /* Memorize the old state of RF */
+                BOOLEAN OldRf = State->Flags.Rf;
+
+                State->Flags.Long = NewFlags;
+
+                /* Restore VM and RF */
+                State->Flags.Vm = FALSE;
+                State->Flags.Rf = OldRf;
+
+                /* Clear VIF and VIP */
+                State->Flags.Vif = State->Flags.Vip = FALSE;
+            }
+            else State->Flags.LowWord = LOWORD(NewFlags);
+
+            /* Restore the reserved bits */
+            State->Flags.AlwaysSet = TRUE;
+            State->Flags.Reserved0 = FALSE;
+            State->Flags.Reserved1 = FALSE;
+        }
+        else
+        {
+            /* User */
+
+            /* Memorize the old state of IF and IOPL */
+            BOOLEAN OldIf = State->Flags.If;
+            UINT OldIopl = State->Flags.Iopl;
+
+            /* Set the flags */
+            if (Size)
+            {
+                /* Memorize the old state of RF */
+                BOOLEAN OldRf = State->Flags.Rf;
+
+                State->Flags.Long = NewFlags;
+
+                /* Restore VM and RF */
+                State->Flags.Vm = FALSE;
+                State->Flags.Rf = OldRf;
+
+                /* Clear VIF and VIP */
+                State->Flags.Vif = State->Flags.Vip = FALSE;
+            }
+            else State->Flags.LowWord = LOWORD(NewFlags);
+
+            /* Restore the reserved bits and IOPL */
+            State->Flags.AlwaysSet = TRUE;
+            State->Flags.Reserved0 = FALSE;
+            State->Flags.Reserved1 = FALSE;
+            State->Flags.Iopl = OldIopl;
+
+            /* Check if the user doesn't have the privilege to change IF */
+            if (Cpl > State->Flags.Iopl)
+            {
+                /* Restore IF */
+                State->Flags.If = OldIf;
+            }
+        }
+    }
+    else
+    {
+        /* Check the IOPL */
+        if (State->Flags.Iopl == 3)
+        {
+            if (Size)
+            {
+                /* Memorize the old state of RF, VIF and VIP */
+                BOOLEAN OldRf = State->Flags.Rf;
+                BOOLEAN OldVif = State->Flags.Vif;
+                BOOLEAN OldVip = State->Flags.Vip;
+
+                State->Flags.Long = NewFlags;
+
+                /* Restore VM, RF, VIF and VIP */
+                State->Flags.Vm = TRUE;
+                State->Flags.Rf = OldRf;
+                State->Flags.Vif = OldVif;
+                State->Flags.Vip = OldVip;
+            }
+            else State->Flags.LowWord = LOWORD(NewFlags);
+
+            /* Restore the reserved bits and IOPL */
+            State->Flags.AlwaysSet = TRUE;
+            State->Flags.Reserved0 = FALSE;
+            State->Flags.Reserved1 = FALSE;
+            State->Flags.Iopl = 3;
+        }
+        else
+        {
+            /* Call the VM86 monitor */
+            Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+        }
+        
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf)
+{
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x9E);
+
+    /* Set the low-order byte of FLAGS to AH */
+    State->Flags.Long &= 0xFFFFFF00;
+    State->Flags.Long |= State->GeneralRegs[SOFT386_REG_EAX].HighByte;
+
+    /* Restore the reserved bits of FLAGS */
+    State->Flags.AlwaysSet = TRUE;
+    State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
+{
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0x9F);
+
+    /* Set AH to the low-order byte of FLAGS */
+    State->GeneralRegs[SOFT386_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
+{
+    ULONG ReturnAddress;
+    USHORT BytesToPop = 0;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xFE) == 0xC2);
+
+    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 (Opcode == 0xC2)
+    {
+        /* Fetch the number of bytes to pop after the return */
+        if (!Soft386FetchWord(State, &BytesToPop)) return FALSE;
+    }
+
+    /* Pop the return address */
+    if (!Soft386StackPop(State, &ReturnAddress)) return FALSE;
+
+    /* Return to the calling procedure, and if necessary, pop the parameters */
+    if (Size)
+    {
+        State->InstPtr.Long = ReturnAddress;
+        State->GeneralRegs[SOFT386_REG_ESP].Long += BytesToPop;
+    }
+    else
+    {
+        State->InstPtr.LowWord = LOWORD(ReturnAddress);
+        State->GeneralRegs[SOFT386_REG_ESP].LowWord += BytesToPop;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes)
+{
+    UCHAR FarPointer[6];
+    BOOLEAN OperandSize, AddressSize;
+    SOFT386_MOD_REG_RM ModRegRm;
+
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xFE) == 0xC4);
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+    {
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
+    }
+
+    /* Get the operands */
+    if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (!ModRegRm.Memory)
+    {
+        /* Check if this is a BOP and the host supports BOPs */
+        if ((Opcode == 0xC4)
+            && (ModRegRm.Register == SOFT386_REG_EAX)
+            && (ModRegRm.SecondRegister == SOFT386_REG_ESP)
+            && (State->BopCallback != NULL))
+        {
+            USHORT BopCode;
+
+            /* Fetch the BOP code */
+            if (!Soft386FetchWord(State, &BopCode))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* Call the BOP handler */
+            State->BopCallback(State, BopCode);
+
+            /* Return success */
+            return TRUE;
+        }
+
+        /* Invalid */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    if (!Soft386ReadMemory(State,
+                           (State->PrefixFlags & SOFT386_PREFIX_SEG)
+                           ? State->SegmentOverride : SOFT386_REG_DS,
+                           ModRegRm.MemoryAddress,
+                           FALSE,
+                           FarPointer,
+                           OperandSize ? 6 : 4))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (OperandSize)
+    {
+        ULONG Offset = *((PULONG)FarPointer);
+        USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
+
+        /* Set the register to the offset */
+        State->GeneralRegs[ModRegRm.Register].Long = Offset;
+
+        /* Load the segment */
+        return Soft386LoadSegment(State,
+                                  (Opcode == 0xC4)
+                                  ? SOFT386_REG_ES : SOFT386_REG_DS,
+                                  Segment);
+    }
+    else
+    {
+        USHORT Offset = *((PUSHORT)FarPointer);
+        USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
+
+        /* Set the register to the offset */
+        State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
+
+        /* Load the segment */
+        return Soft386LoadSegment(State,
+                                  (Opcode == 0xC4)
+                                  ? SOFT386_REG_ES : SOFT386_REG_DS,
+                                  Segment);
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter)
+{
+    INT i;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    USHORT FrameSize;
+    UCHAR NestingLevel;
+    SOFT386_REG FramePointer;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xC8);
+
+    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 (!Soft386FetchWord(State, &FrameSize))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (!Soft386FetchByte(State, &NestingLevel))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Push EBP */
+    if (!Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Save ESP */
+    FramePointer = State->GeneralRegs[SOFT386_REG_ESP];
+
+    /* Set up the nested procedure stacks */
+    for (i = 1; i < NestingLevel; i++)
+    {
+        if (Size)
+        {
+            State->GeneralRegs[SOFT386_REG_EBP].Long -= 4;
+            Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long);
+        }
+        else
+        {
+            State->GeneralRegs[SOFT386_REG_EBP].LowWord -= 2;
+            Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].LowWord);
+        }
+    }
+
+    if (NestingLevel > 0) Soft386StackPush(State, FramePointer.Long);
+
+    /* Set EBP to the frame pointer */
+    State->GeneralRegs[SOFT386_REG_EBP] = FramePointer;
+
+    /* Reserve space for the frame */
+    if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long -= (ULONG)FrameSize;
+    else State->GeneralRegs[SOFT386_REG_ESP].LowWord -= FrameSize;
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xC9);
+
+    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)
+    {
+        /* Set the stack pointer (ESP) to the base pointer (EBP) */
+        State->GeneralRegs[SOFT386_REG_ESP].Long = State->GeneralRegs[SOFT386_REG_EBP].Long;
+
+        /* Pop the saved base pointer from the stack */
+        return Soft386StackPop(State, &State->GeneralRegs[SOFT386_REG_EBP].Long);
+    }
+    else
+    {
+        ULONG Value;
+
+        /* Set the stack pointer (SP) to the base pointer (BP) */
+        State->GeneralRegs[SOFT386_REG_ESP].LowWord = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
+
+        /* Pop the saved base pointer from the stack */
+        if (Soft386StackPop(State, &Value))
+        {
+            State->GeneralRegs[SOFT386_REG_EBP].LowWord = LOWORD(Value);
+            return TRUE;
+        }
+        else return FALSE;
+    }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm)
+{
+    // TODO: NOT IMPLEMENTED
+    UNIMPLEMENTED;
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar)
+{
+    // TODO: NOT IMPLEMENTED
+    UNIMPLEMENTED;
+
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeInt)
+{
+    UCHAR IntNum;
+    SOFT386_IDT_ENTRY IdtEntry;
+
+    switch (Opcode)
+    {
+        case 0xCC:
+        {
+            /* This is the INT3 instruction */
+            IntNum = 3;
+            break;
+        }
+
+        case 0xCD:
+        {
+            /* Fetch the interrupt number */
+            if (!Soft386FetchByte(State, &IntNum))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            break;
+        }
+
+        case 0xCE:
+        {
+            /* Don't do anything if OF is cleared */
+            if (!State->Flags.Of) return TRUE;
+
+            /* Exception #OF */
+            IntNum = SOFT386_EXCEPTION_OF;
+
+            break;
+        }
+
+        default:
+        {
+            /* Should not happen */
+            ASSERT(FALSE);
+        }
+    }
+
+    /* Get the interrupt vector */
+    if (!Soft386GetIntVector(State, IntNum, &IdtEntry))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Perform the interrupt */
+    if (!Soft386InterruptInternal(State,
+                                  IdtEntry.Selector,
+                                  MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
+                                  IdtEntry.Type))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIret)
+{
+    INT i;
+    ULONG InstPtr, CodeSel, StackPtr, StackSel;
+    SOFT386_FLAGS_REG NewFlags;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xCF);
+
+    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;
+    }
+
+    /* Pop EIP */
+    if (!Soft386StackPop(State, &InstPtr))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Pop CS */
+    if (!Soft386StackPop(State, &CodeSel))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Pop EFLAGS */
+    if (!Soft386StackPop(State, &NewFlags.Long))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Check for protected mode */
+    if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+    {
+        INT Cpl = Soft386GetCurrentPrivLevel(State);
+
+        if (State->Flags.Vm)
+        {
+            /* Return from VM86 mode */
+
+            /* Check the IOPL */
+            if (State->Flags.Iopl == 3)
+            {
+                /* Set new EIP */
+                State->InstPtr.Long = LOWORD(InstPtr);
+
+                /* Load new CS */
+                if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+                {
+                    /* Exception occurred */
+                    return FALSE;
+                }
+
+                /* Set the new flags */
+                if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+                else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+                State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
+                State->Flags.Iopl = 3;
+            }
+            else
+            {
+                /* Call the VM86 monitor */
+                Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+                return FALSE;
+            }
+
+            return TRUE;
+        }
+
+        if (State->Flags.Nt)
+        {
+            /* Nested task return */
+
+            UNIMPLEMENTED;
+            return FALSE;
+        }
+
+        if (NewFlags.Vm)
+        {
+            /* Return to VM86 mode */
+            ULONG Es, Ds, Fs, Gs;
+
+            /* Pop ESP, SS, ES, FS, GS */
+            if (!Soft386StackPop(State, &StackPtr)) return FALSE;
+            if (!Soft386StackPop(State, &StackSel)) return FALSE;
+            if (!Soft386StackPop(State, &Es)) return FALSE;
+            if (!Soft386StackPop(State, &Ds)) return FALSE;
+            if (!Soft386StackPop(State, &Fs)) return FALSE;
+            if (!Soft386StackPop(State, &Gs)) return FALSE;
+
+            /* Set the new IP */
+            State->InstPtr.Long = LOWORD(InstPtr);
+
+            /* Set the new flags */
+            if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+            else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+            State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
+
+            /* Load the new segments */
+            if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel)) return FALSE;
+            if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel)) return FALSE;
+            if (!Soft386LoadSegment(State, SOFT386_REG_ES, Es)) return FALSE;
+            if (!Soft386LoadSegment(State, SOFT386_REG_DS, Ds)) return FALSE;
+            if (!Soft386LoadSegment(State, SOFT386_REG_FS, Fs)) return FALSE;
+            if (!Soft386LoadSegment(State, SOFT386_REG_GS, Gs)) return FALSE;
+
+            return TRUE;
+        }
+
+        /* Load the new CS */
+        if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Set EIP */
+        if (Size) State->InstPtr.Long = InstPtr;
+        else State->InstPtr.LowWord = LOWORD(InstPtr);
+
+        if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+        {
+            /* Pop ESP */
+            if (!Soft386StackPop(State, &StackPtr))
+            {
+                /* Exception */
+                return FALSE;
+            }
+
+            /* Pop SS */
+            if (!Soft386StackPop(State, &StackSel))
+            {
+                /* Exception */
+                return FALSE;
+            }
+
+            /* Load new SS */
+            if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel))
+            {
+                /* Exception */
+                return FALSE;
+            }
+
+            /* Set ESP */
+            if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long = StackPtr;
+            else State->GeneralRegs[SOFT386_REG_ESP].LowWord = LOWORD(StackPtr);
+        }
+
+        /* Set the new flags */
+        if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
+        else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
+        State->Flags.AlwaysSet = TRUE;
+
+        /* Set additional flags */
+        if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
+        if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
+
+        if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+        {
+            /* Update the CPL */
+            Cpl = Soft386GetCurrentPrivLevel(State);
+
+            /* Check segment security */
+            for (i = 0; i <= SOFT386_NUM_SEG_REGS; i++)
+            {
+                /* Don't check CS or SS */
+                if ((i == SOFT386_REG_CS) || (i == SOFT386_REG_SS)) continue;
+
+                if ((Cpl > State->SegmentRegs[i].Dpl)
+                    && (!State->SegmentRegs[i].Executable
+                    || !State->SegmentRegs[i].DirConf))
+                {
+                    /* Load the NULL descriptor in the segment */
+                    if (!Soft386LoadSegment(State, i, 0)) return FALSE;
+                }
+            }
+        }
+    }
+    else
+    {
+        if (Size && (InstPtr & 0xFFFF0000))
+        {
+            /* Invalid */
+            Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+            return FALSE;
+        }
+
+        /* Set new EIP */
+        State->InstPtr.Long = InstPtr;
+
+        /* Load new CS */
+        if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Set the new flags */
+        if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+        else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+        State->Flags.AlwaysSet = TRUE;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAam)
+{
+    UCHAR Base;
+    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    {
+        /* Invalid prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    /* Fetch the base */
+    if (!Soft386FetchByte(State, &Base))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Check if the base is zero */
+    if (Base == 0)
+    {
+        /* Divide error */
+        Soft386Exception(State, SOFT386_EXCEPTION_DE);
+        return FALSE;
+    }
+
+    /* Adjust */
+    State->GeneralRegs[SOFT386_REG_EAX].HighByte = Value / Base;
+    State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value %= Base;
+
+    /* Update flags */
+    State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+    State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+    State->Flags.Pf = Soft386CalculateParity(Value);
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
+{
+    UCHAR Base;
+    UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    {
+        /* Invalid prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    /* Fetch the base */
+    if (!Soft386FetchByte(State, &Base))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Adjust */
+    Value += State->GeneralRegs[SOFT386_REG_EAX].HighByte * Base;
+    State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value;
+
+    /* Update flags */
+    State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+    State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+    State->Flags.Pf = Soft386CalculateParity(Value);
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
+{
+    UCHAR Value;
+    BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    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)
+{
+    BOOLEAN Condition;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    CHAR Offset = 0;
+
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
+
+    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) Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].Long) != 0);
+    else Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) != 0);
+
+    if (Opcode == 0xE0)
+    {
+        /* Additional rule for LOOPNZ */
+        if (State->Flags.Zf) Condition = FALSE;
+    }
+
+    if (Opcode == 0xE1)
+    {
+        /* Additional rule for LOOPZ */
+        if (!State->Flags.Zf) Condition = FALSE;
+    }
+
+    /* Fetch the offset */
+    if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+    {
+        /* An exception occurred */
+        return FALSE;
+    }
+
+    if (Condition)
+    {
+        /* Move the instruction pointer */
+        State->InstPtr.Long += Offset;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
+{
+    BOOLEAN Condition;
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    CHAR Offset = 0;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xE3);
+
+    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) Condition = (State->GeneralRegs[SOFT386_REG_ECX].Long == 0);
+    else Condition = (State->GeneralRegs[SOFT386_REG_ECX].LowWord == 0);
+
+    /* Fetch the offset */
+    if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+    {
+        /* An exception occurred */
+        return FALSE;
+    }
+
+    if (Condition)
+    {
+        /* Move the instruction pointer */        
+        State->InstPtr.Long += Offset;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCall)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xE8);
+
+    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;
+    }
+
+    if (Size)
+    {
+        LONG Offset = 0;
+
+        /* Fetch the offset */
+        if (!Soft386FetchDword(State, (PULONG)&Offset))
+        {
+            /* An exception occurred */
+            return FALSE;
+        }
+
+        /* Push the current value of the instruction pointer */
+        if (!Soft386StackPush(State, State->InstPtr.Long))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Move the instruction pointer */        
+        State->InstPtr.Long += Offset;
+    }
+    else
+    {
+        SHORT Offset = 0;
+
+        /* Fetch the offset */
+        if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+        {
+            /* An exception occurred */
+            return FALSE;
+        }
+
+        /* Push the current value of the instruction pointer */
+        if (!Soft386StackPush(State, State->InstPtr.Long))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Move the instruction pointer */        
+        State->InstPtr.LowWord += Offset;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xE9);
+
+    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;
+    }
+
+    if (Size)
+    {
+        LONG Offset = 0;
+
+        /* Fetch the offset */
+        if (!Soft386FetchDword(State, (PULONG)&Offset))
+        {
+            /* An exception occurred */
+            return FALSE;
+        }
+
+        /* Move the instruction pointer */        
+        State->InstPtr.Long += Offset;
+    }
+    else
+    {
+        SHORT Offset = 0;
+
+        /* Fetch the offset */
+        if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+        {
+            /* An exception occurred */
+            return FALSE;
+        }
+
+        /* Move the instruction pointer */        
+        State->InstPtr.LowWord += Offset;
+    }
+
+    return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
 {
     // TODO: NOT IMPLEMENTED
     UNIMPLEMENTED;
 
-    return FALSE;
-}
+    return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    ULONG Offset;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xA0);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
+    if (Size)
+    {
+        if (!Soft386FetchDword(State, &Offset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+    }
+    else
+    {
+        USHORT WordOffset;
+
+        if (!Soft386FetchWord(State, &WordOffset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        Offset = (ULONG)WordOffset;
+    }
+
+    /* Read from memory */
+    return Soft386ReadMemory(State,
+                             (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                             State->SegmentOverride : SOFT386_REG_DS,
+                             Offset,
+                             FALSE,
+                             &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+                             sizeof(UCHAR));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xA1);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+    {
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
+    if (Size)
+    {
+        ULONG Offset;
+
+        if (!Soft386FetchDword(State, &Offset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+        /* Read from memory */
+        return Soft386ReadMemory(State,
+                                 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                                 State->SegmentOverride : SOFT386_REG_DS,
+                                 Offset,
+                                 FALSE,
+                                 &State->GeneralRegs[SOFT386_REG_EAX].Long,
+                                 sizeof(ULONG));
+    }
+    else
+    {
+        USHORT Offset;
 
-    return FALSE;
+        if (!Soft386FetchWord(State, &Offset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Read from memory */
+        return Soft386ReadMemory(State,
+                                 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                                 State->SegmentOverride : SOFT386_REG_DS,
+                                 Offset,
+                                 FALSE,
+                                 &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+                                 sizeof(USHORT));
+    }
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl)
 {
     BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    ULONG Offset;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0xC9);
+    ASSERT(Opcode == 0xA2);
 
-    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        /* The OPSIZE prefix toggles the size */
+        Size = !Size;
+    }
+
+    if (Size)
+    {
+        if (!Soft386FetchDword(State, &Offset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+    }
+    else
+    {
+        USHORT WordOffset;
+
+        if (!Soft386FetchWord(State, &WordOffset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        Offset = (ULONG)WordOffset;
     }
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    /* Write to memory */
+    return Soft386WriteMemory(State,
+                             (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                             State->SegmentOverride : SOFT386_REG_DS,
+                             Offset,
+                             &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+                             sizeof(UCHAR));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax)
+{
+    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xA3);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
         /* The OPSIZE prefix toggles the size */
         Size = !Size;
@@ -4228,308 +5853,822 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave)
 
     if (Size)
     {
-        /* Set the stack pointer (ESP) to the base pointer (EBP) */
-        State->GeneralRegs[SOFT386_REG_ESP].Long = State->GeneralRegs[SOFT386_REG_EBP].Long;
+        ULONG Offset;
 
-        /* Pop the saved base pointer from the stack */
-        return Soft386StackPop(State, &State->GeneralRegs[SOFT386_REG_EBP].Long);
+        if (!Soft386FetchDword(State, &Offset))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Write to memory */
+        return Soft386WriteMemory(State,
+                                  (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                                  State->SegmentOverride : SOFT386_REG_DS,
+                                  Offset,
+                                  &State->GeneralRegs[SOFT386_REG_EAX].Long,
+                                  sizeof(ULONG));
     }
     else
     {
-        ULONG Value;
-
-        /* Set the stack pointer (SP) to the base pointer (BP) */
-        State->GeneralRegs[SOFT386_REG_ESP].LowWord = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
+        USHORT Offset;
 
-        /* Pop the saved base pointer from the stack */
-        if (Soft386StackPop(State, &Value))
+        if (!Soft386FetchWord(State, &Offset))
         {
-            State->GeneralRegs[SOFT386_REG_EBP].LowWord = LOWORD(Value);
-            return TRUE;
+            /* Exception occurred */
+            return FALSE;
         }
-        else return FALSE;
+
+        /* Write to memory */
+        return Soft386WriteMemory(State,
+                                  (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+                                  State->SegmentOverride : SOFT386_REG_DS,
+                                  Offset,
+                                  &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+                                  sizeof(USHORT));
     }
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSalc)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    /* Make sure this is the right instruction */
+    ASSERT(Opcode == 0xD6);
 
-    return FALSE;
-}
+    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    {
+        /* Invalid prefix */
+        Soft386Exception(State, SOFT386_EXCEPTION_UD);
+        return FALSE;
+    }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    /* Set all the bits of AL to CF */
+    State->GeneralRegs[SOFT386_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
 
-    return FALSE;
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeInt3)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    ULONG Data, DataSize;
+    BOOLEAN OperandSize, AddressSize;
 
-    return FALSE;
-}
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeInt)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    /* Make sure this is the right instruction */
+    ASSERT((Opcode & 0xFE) == 0xA4);
 
-    return FALSE;
+    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 == 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))
+    {
+        /* 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
+    {
+        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(Soft386OpcodeIntOverflow)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    ULONG FirstValue = 0, SecondValue = 0, Result;
+    ULONG DataSize, DataMask, SignFlag;
+    BOOLEAN OperandSize, AddressSize;
 
-    return FALSE;
+    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(Soft386OpcodeIret)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+    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;
+    }
+
+    /* Calculate the size */
+    if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
+    else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_REP)
+    {
+        UCHAR Block[STRING_BLOCK_SIZE];
+        ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+                                  : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
+
+        /* 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);
+
+            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;
+            }
 
-    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);
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAam)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+                /* Exception occurred */
+                return FALSE;
+            }
 
-    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;
+            }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+            /* Reduce the total count by the number processed in this run */
+            Count -= Processed;
+        }
 
-    return FALSE;
-}
+        /* Clear ECX */
+        if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+        else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
+    }
+    else
+    {
+        /* 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;
+        }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+        /* 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 FALSE;
+    /* Return success */
+    return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
 {
-    BOOLEAN Condition;
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-    CHAR Offset = 0;
+    ULONG DataSize;
+    BOOLEAN OperandSize, AddressSize;
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
     /* Make sure this is the right instruction */
-    ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
+    ASSERT((Opcode & 0xFE) == 0xAC);
 
-    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        /* The OPSIZE prefix toggles the size */
+        OperandSize = !OperandSize;
     }
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
     }
 
-    if (Size) Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0);
-    else Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0);
+    /* Calculate the size */
+    if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
+    else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
 
-    if (Opcode == 0xE0)
+    if (State->PrefixFlags & SOFT386_PREFIX_REP)
     {
-        /* Additional rule for LOOPNZ */
-        if (State->Flags.Zf) Condition = FALSE;
-    }
+        ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+                                  : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
 
-    if (Opcode == 0xE1)
-    {
-        /* Additional rule for LOOPZ */
-        if (!State->Flags.Zf) Condition = FALSE;
+        /* 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;
+        }
     }
 
-    /* Fetch the offset */
-    if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+    /* 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,
+                           &State->GeneralRegs[SOFT386_REG_EAX].Long,
+                           DataSize))
     {
-        /* An exception occurred */
+        /* Exception occurred */
         return FALSE;
     }
 
-    if (Condition)
+    /* Increment/decrement ESI */
+    if (OperandSize)
     {
-        /* Move the instruction pointer */
-        State->InstPtr.Long += Offset;
+        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 */
     return TRUE;
 }
 
-SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
 {
-    BOOLEAN Condition;
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-    CHAR Offset = 0;
+    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 == 0xE3);
+    ASSERT((Opcode & 0xFE) == 0xAE);
 
-    if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        /* The OPSIZE prefix toggles the size */
+        OperandSize = !OperandSize;
     }
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* The OPSIZE prefix toggles the size */
-        Size = !Size;
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
     }
 
-    if (Size) Condition = (State->GeneralRegs[SOFT386_REG_ECX].Long == 0);
-    else Condition = (State->GeneralRegs[SOFT386_REG_ECX].LowWord == 0);
+    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;
+    }
 
-    /* Fetch the offset */
-    if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+    /* 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))
     {
-        /* An exception occurred */
+        /* Exception occurred */
         return FALSE;
     }
 
-    if (Condition)
+    /* 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)
     {
-        /* Move the instruction pointer */        
-        State->InstPtr.Long += Offset;
+        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(Soft386OpcodeCall)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
 {
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    ULONG DataSize;
+    BOOLEAN OperandSize, AddressSize;
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0xE8);
+    ASSERT((Opcode & 0xFE) == 0x6C);
 
-    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)
-    {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        OperandSize = !OperandSize;
     }
 
-    /* Push the current value of the instruction pointer */
-    if (!Soft386StackPush(State, State->InstPtr.Long))
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* Exception occurred */
-        return FALSE;
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
     }
 
-    if (Size)
+    /* Calculate the size */
+    if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
+    else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_REP)
     {
-        LONG Offset = 0;
+        UCHAR Block[STRING_BLOCK_SIZE];
+        ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+                                  : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
 
-        /* Fetch the offset */
-        if (!Soft386FetchDword(State, (PULONG)&Offset))
+        /* Clear the memory block */
+        RtlZeroMemory(Block, sizeof(Block));
+
+        /* Transfer until finished */
+        while (Count)
         {
-            /* An exception occurred */
-            return FALSE;
+            ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+            /* 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;
         }
 
-        /* Move the instruction pointer */        
-        State->InstPtr.Long += Offset;
+        /* Clear ECX */
+        if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+        else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
     }
     else
     {
-        SHORT Offset = 0;
-
-        /* Fetch the offset */
-        if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+        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))
         {
-            /* An exception occurred */
+            /* Exception occurred */
             return FALSE;
         }
 
-        /* Move the instruction pointer */        
-        State->InstPtr.LowWord += Offset;
+        /* 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(Soft386OpcodeJmp)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
 {
-    BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+    ULONG DataSize;
+    BOOLEAN OperandSize, AddressSize;
+
+    OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
 
     /* Make sure this is the right instruction */
-    ASSERT(Opcode == 0xE9);
+    ASSERT((Opcode & 0xFE) == 0x6E);
 
-    if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+    if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
     {
         /* The OPSIZE prefix toggles the size */
-        Size = !Size;
+        OperandSize = !OperandSize;
     }
-    else if (State->PrefixFlags != 0)
+
+    if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
     {
-        /* Invalid prefix */
-        Soft386Exception(State, SOFT386_EXCEPTION_UD);
-        return FALSE;
+        /* The ADSIZE prefix toggles the size */
+        AddressSize = !AddressSize;
     }
 
-    if (Size)
+    /* Calculate the size */
+    if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
+    else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+    if (State->PrefixFlags & SOFT386_PREFIX_REP)
     {
-        LONG Offset = 0;
+        UCHAR Block[STRING_BLOCK_SIZE];
+        ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+                                  : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
 
-        /* Fetch the offset */
-        if (!Soft386FetchDword(State, (PULONG)&Offset))
+        /* Clear the memory block */
+        RtlZeroMemory(Block, sizeof(Block));
+
+        /* Transfer until finished */
+        while (Count)
         {
-            /* An exception occurred */
-            return FALSE;
+            ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+            /* 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;
         }
 
-        /* Move the instruction pointer */        
-        State->InstPtr.Long += Offset;
+        /* Clear ECX */
+        if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+        else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
     }
     else
     {
-        SHORT Offset = 0;
+        ULONG Data = 0;
 
-        /* Fetch the offset */
-        if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+        /* 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))
         {
-            /* An exception occurred */
+            /* Exception occurred */
             return FALSE;
         }
 
-        /* Move the instruction pointer */        
-        State->InstPtr.LowWord += Offset;
+        /* 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 */
     return TRUE;
 }
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
-
-    return FALSE;
-}