/*
- * 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"
-// #define NDEBUG
-#include <debug.h>
-
/* PUBLIC VARIABLES ***********************************************************/
SOFT386_OPCODE_HANDLER_PROC
Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
{
- NULL, // TODO: OPCODE 0x00 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x01 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x02 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x03 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x04 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x05 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x06 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x07 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x08 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x09 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x0F NOT SUPPORTED
- NULL, // TODO: OPCODE 0x10 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x11 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x12 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x13 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x14 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x15 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x16 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x17 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x18 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x19 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x1F NOT SUPPORTED
- NULL, // TODO: OPCODE 0x20 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x21 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x22 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x23 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x24 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x25 NOT SUPPORTED
+ Soft386OpcodeAddByteModrm,
+ Soft386OpcodeAddModrm,
+ Soft386OpcodeAddByteModrm,
+ Soft386OpcodeAddModrm,
+ Soft386OpcodeAddAl,
+ Soft386OpcodeAddEax,
+ Soft386OpcodePushEs,
+ Soft386OpcodePopEs,
+ Soft386OpcodeOrByteModrm,
+ Soft386OpcodeOrModrm,
+ Soft386OpcodeOrByteModrm,
+ Soft386OpcodeOrModrm,
+ Soft386OpcodeOrAl,
+ Soft386OpcodeOrEax,
+ Soft386OpcodePushCs,
+ Soft386OpcodeExtended,
+ Soft386OpcodeAdcByteModrm,
+ Soft386OpcodeAdcModrm,
+ Soft386OpcodeAdcByteModrm,
+ Soft386OpcodeAdcModrm,
+ Soft386OpcodeAdcAl,
+ Soft386OpcodeAdcEax,
+ Soft386OpcodePushSs,
+ Soft386OpcodePopSs,
+ Soft386OpcodeSbbByteModrm,
+ Soft386OpcodeSbbModrm,
+ Soft386OpcodeSbbByteModrm,
+ Soft386OpcodeSbbModrm,
+ Soft386OpcodeSbbAl,
+ Soft386OpcodeSbbEax,
+ Soft386OpcodePushDs,
+ Soft386OpcodePopDs,
+ Soft386OpcodeAndByteModrm,
+ Soft386OpcodeAndModrm,
+ Soft386OpcodeAndByteModrm,
+ Soft386OpcodeAndModrm,
+ Soft386OpcodeAndAl,
+ Soft386OpcodeAndEax,
Soft386OpcodePrefix,
- NULL, // TODO: OPCODE 0x27 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x28 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x29 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x2A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x2B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x2C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x2D NOT SUPPORTED
+ Soft386OpcodeDaa,
+ Soft386OpcodeCmpSubByteModrm,
+ Soft386OpcodeCmpSubModrm,
+ Soft386OpcodeCmpSubByteModrm,
+ Soft386OpcodeCmpSubModrm,
+ Soft386OpcodeCmpSubAl,
+ Soft386OpcodeCmpSubEax,
Soft386OpcodePrefix,
- NULL, // TODO: OPCODE 0x2F NOT SUPPORTED
- NULL, // TODO: OPCODE 0x30 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x31 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x32 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x33 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x34 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x35 NOT SUPPORTED
+ Soft386OpcodeDas,
+ Soft386OpcodeXorByteModrm,
+ Soft386OpcodeXorModrm,
+ Soft386OpcodeXorByteModrm,
+ Soft386OpcodeXorModrm,
+ Soft386OpcodeXorAl,
+ Soft386OpcodeXorEax,
Soft386OpcodePrefix,
- NULL, // TODO: OPCODE 0x37 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x38 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x39 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x3A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x3B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x3C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x3D NOT SUPPORTED
+ Soft386OpcodeAaa,
+ Soft386OpcodeCmpSubByteModrm,
+ Soft386OpcodeCmpSubModrm,
+ Soft386OpcodeCmpSubByteModrm,
+ Soft386OpcodeCmpSubModrm,
+ Soft386OpcodeCmpSubAl,
+ Soft386OpcodeCmpSubEax,
Soft386OpcodePrefix,
- NULL, // TODO: OPCODE 0x3F NOT SUPPORTED
+ Soft386OpcodeAas,
Soft386OpcodeIncrement,
Soft386OpcodeIncrement,
Soft386OpcodeIncrement,
Soft386OpcodePopReg,
Soft386OpcodePopReg,
Soft386OpcodePopReg,
- NULL, // TODO: OPCODE 0x60 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x61 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x62 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x63 NOT SUPPORTED
+ Soft386OpcodePushAll,
+ Soft386OpcodePopAll,
+ Soft386OpcodeBound,
+ Soft386OpcodeArpl,
Soft386OpcodePrefix,
Soft386OpcodePrefix,
Soft386OpcodePrefix,
Soft386OpcodePrefix,
- NULL, // TODO: OPCODE 0x68 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x69 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6F NOT SUPPORTED
+ Soft386OpcodePushImm,
+ Soft386OpcodeImulModrmImm,
+ Soft386OpcodePushByteImm,
+ Soft386OpcodeImulModrmImm,
+ Soft386OpcodeIns,
+ Soft386OpcodeIns,
+ Soft386OpcodeOuts,
+ Soft386OpcodeOuts,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
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
- NULL, // TODO: OPCODE 0x84 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x85 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x86 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x87 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x88 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x89 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x8F NOT SUPPORTED
+ Soft386OpcodeGroup8082,
+ Soft386OpcodeGroup81,
+ Soft386OpcodeGroup8082,
+ Soft386OpcodeGroup83,
+ Soft386OpcodeTestByteModrm,
+ Soft386OpcodeTestModrm,
+ Soft386OpcodeXchgByteModrm,
+ Soft386OpcodeXchgModrm,
+ Soft386OpcodeMovByteModrm,
+ Soft386OpcodeMovModrm,
+ Soft386OpcodeMovByteModrm,
+ Soft386OpcodeMovModrm,
+ Soft386OpcodeMovStoreSeg,
+ Soft386OpcodeLea,
+ Soft386OpcodeMovLoadSeg,
+ Soft386OpcodeGroup8F,
Soft386OpcodeNop,
Soft386OpcodeExchangeEax,
Soft386OpcodeExchangeEax,
Soft386OpcodeExchangeEax,
Soft386OpcodeExchangeEax,
Soft386OpcodeExchangeEax,
- NULL, // TODO: OPCODE 0x98 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x99 NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9A NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9B NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x9F NOT SUPPORTED
- 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
- NULL, // TODO: OPCODE 0xA8 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA9 NOT SUPPORTED
- 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
+ Soft386OpcodeCwde,
+ Soft386OpcodeCdq,
+ Soft386OpcodeCallAbs,
+ Soft386OpcodeWait,
+ Soft386OpcodePushFlags,
+ Soft386OpcodePopFlags,
+ Soft386OpcodeSahf,
+ Soft386OpcodeLahf,
+ Soft386OpcodeMovAlOffset,
+ Soft386OpcodeMovEaxOffset,
+ Soft386OpcodeMovOffsetAl,
+ Soft386OpcodeMovOffsetEax,
+ Soft386OpcodeMovs,
+ Soft386OpcodeMovs,
+ Soft386OpcodeCmps,
+ Soft386OpcodeCmps,
+ Soft386OpcodeTestAl,
+ Soft386OpcodeTestEax,
+ Soft386OpcodeStos,
+ Soft386OpcodeStos,
+ Soft386OpcodeLods,
+ Soft386OpcodeLods,
+ Soft386OpcodeScas,
+ Soft386OpcodeScas,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeMovRegImm,
Soft386OpcodeMovRegImm,
Soft386OpcodeMovRegImm,
- NULL, // TODO: OPCODE 0xC0 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC1 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC2 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC3 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC4 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC5 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC6 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC7 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC8 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xC9 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCA NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCB NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCC NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCD NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCE NOT SUPPORTED
- NULL, // TODO: OPCODE 0xCF NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD0 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD1 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD2 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD3 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD4 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD5 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD6 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xD7 NOT SUPPORTED
+ Soft386OpcodeGroupC0,
+ Soft386OpcodeGroupC1,
+ Soft386OpcodeRet,
+ Soft386OpcodeRet,
+ Soft386OpcodeLdsLes,
+ Soft386OpcodeLdsLes,
+ Soft386OpcodeGroupC6,
+ Soft386OpcodeGroupC7,
+ Soft386OpcodeEnter,
+ Soft386OpcodeLeave,
+ Soft386OpcodeRetFarImm,
+ Soft386OpcodeRetFar,
+ Soft386OpcodeInt,
+ Soft386OpcodeInt,
+ Soft386OpcodeInt,
+ Soft386OpcodeIret,
+ Soft386OpcodeGroupD0,
+ Soft386OpcodeGroupD1,
+ Soft386OpcodeGroupD2,
+ Soft386OpcodeGroupD3,
+ Soft386OpcodeAam,
+ Soft386OpcodeAad,
+ Soft386OpcodeSalc,
+ Soft386OpcodeXlat,
NULL, // TODO: OPCODE 0xD8 NOT SUPPORTED
NULL, // TODO: OPCODE 0xD9 NOT SUPPORTED
NULL, // TODO: OPCODE 0xDA NOT SUPPORTED
NULL, // TODO: OPCODE 0xDD NOT SUPPORTED
NULL, // TODO: OPCODE 0xDE NOT SUPPORTED
NULL, // TODO: OPCODE 0xDF NOT SUPPORTED
- NULL, // TODO: OPCODE 0xE0 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xE1 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xE2 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xE3 NOT SUPPORTED
+ Soft386OpcodeLoop,
+ Soft386OpcodeLoop,
+ Soft386OpcodeLoop,
+ Soft386OpcodeJecxz,
Soft386OpcodeInByte,
Soft386OpcodeIn,
Soft386OpcodeOutByte,
Soft386OpcodeOut,
- NULL, // TODO: OPCODE 0xE8 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xE9 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xEA NOT SUPPORTED
+ Soft386OpcodeCall,
+ Soft386OpcodeJmp,
+ Soft386OpcodeJmpAbs,
Soft386OpcodeShortJump,
Soft386OpcodeInByte,
Soft386OpcodeIn,
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,
};
-BOOLEAN
-FASTCALL
-Soft386OpcodePrefix(PSOFT386_STATE State, UCHAR Opcode)
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePrefix)
{
BOOLEAN Valid = FALSE;
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeIncrement(PSOFT386_STATE State, UCHAR Opcode)
+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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeDecrement(PSOFT386_STATE State, UCHAR Opcode)
+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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodePushReg(PSOFT386_STATE State, UCHAR Opcode)
+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);
return Soft386StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
}
-BOOLEAN
-FASTCALL
-Soft386OpcodePopReg(PSOFT386_STATE State, UCHAR Opcode)
+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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeNop(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeNop)
{
if (State->PrefixFlags & ~(SOFT386_PREFIX_OPSIZE | SOFT386_PREFIX_REP))
{
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeExchangeEax(PSOFT386_STATE State, UCHAR Opcode)
+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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeShortConditionalJmp(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeShortConditionalJmp)
{
BOOLEAN Jump = FALSE;
CHAR Offset = 0;
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeClearCarry(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeClearCarry)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xF8);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeSetCarry(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSetCarry)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xF9);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeComplCarry(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeComplCarry)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xF5);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeClearInt(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeClearInt)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xFA);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeSetInt(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSetInt)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xFB);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeClearDir(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeClearDir)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xFC);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeSetDir(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSetDir)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xFD);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeHalt(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeHalt)
{
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xF4);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeInByte(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeInByte)
{
UCHAR Data;
ULONG Port;
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeIn(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIn)
{
ULONG Port;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
/* 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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeOutByte(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOutByte)
{
UCHAR Data;
ULONG Port;
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeOut(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOut)
{
ULONG Port;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
/* 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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeShortJump(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeShortJump)
{
CHAR Offset = 0;
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeMovRegImm(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm)
{
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
/* 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);
return TRUE;
}
-BOOLEAN
-FASTCALL
-Soft386OpcodeMovByteRegImm(PSOFT386_STATE State, UCHAR Opcode)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteRegImm)
{
UCHAR Value;
return TRUE;
}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAddByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x00);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAddModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x01);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAddAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x04);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x05);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = (Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOrByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x08);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOrModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x09);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOrAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x0C);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x0D);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue | SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAndByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x20);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAndModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x21);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x24);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x25);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x30);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x31);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x34);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x35);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue ^ SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x84);
+
+ 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;
+ }
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* The result is discarded */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x85);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+ }
+ else
+ {
+ USHORT FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+ }
+
+ /* The result is discarded */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeTestAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA8);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* The result is discarded */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA9);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue & SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FALSE;
+ State->Flags.Of = FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+ }
+
+ /* The result is discarded */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm)
+{
+ UCHAR FirstValue, SecondValue;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x86);
+
+ 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;
+ }
+
+ /* Write the value from the register to the R/M */
+ if (!Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ FALSE,
+ FirstValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write the value from the R/M to the register */
+ if (!Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ TRUE,
+ SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x87);
+
+ 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;
+
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write the value from the register to the R/M */
+ if (!Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ FALSE,
+ FirstValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write the value from the R/M to the register */
+ if (!Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ TRUE,
+ SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
+ {
+ USHORT FirstValue, SecondValue;
+
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write the value from the register to the R/M */
+ if (!Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ FALSE,
+ FirstValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write the value from the R/M to the register */
+ if (!Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ TRUE,
+ SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+
+ /* The result is discarded */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushEs)
+{
+ /* Call the internal API */
+ return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_ES].Selector);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopEs)
+{
+ ULONG NewSelector;
+
+ if (!Soft386StackPop(State, &NewSelector))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386LoadSegment(State, SOFT386_REG_ES, LOWORD(NewSelector));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushCs)
+{
+ /* Call the internal API */
+ return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_CS].Selector);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x10);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf
+ && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x11);
+
+ 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf
+ && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf
+ && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x14);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf &&
+ ((FirstValue == 0xFF) || (SecondValue == 0xFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x15);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf &&
+ ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue + SecondValue + State->Flags.Cf;
+
+ /* Special exception for CF */
+ State->Flags.Cf = State->Flags.Cf &&
+ ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
+
+ /* Update the flags */
+ State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < 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)) & 0x10) ? TRUE : FALSE;
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushSs)
+{
+ /* Call the internal API */
+ return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_SS].Selector);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs)
+{
+ ULONG NewSelector;
+
+ if (!Soft386StackPop(State, &NewSelector))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386LoadSegment(State, SOFT386_REG_SS, LOWORD(NewSelector));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm)
+{
+ 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 & 0xFD) == 0x18);
+
+ 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 (!Soft386ReadModrmByteOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue - Carry;
+
+ /* Update the flags */
+ 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 + 1) & 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 Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+}
+
+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 & 0xFD) == 0x19);
+
+ 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;
+ }
+
+ /* Check the operand size */
+ if (OperandSize)
+ {
+ ULONG FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue - Carry;
+
+ /* Update the flags */
+ 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 + 1) & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* 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;
+ }
+
+ /* 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 - Carry;
+
+ /* Update the flags */
+ 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 + 1) & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+}
+
+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 == 0x1C);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue - Carry;
+
+ /* Update the flags */
+ 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 + 1) & 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 */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+
+ return TRUE;
+
+}
+
+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 == 0x1D);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue - Carry;
+
+ /* Update the flags */
+ 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 + Carry) & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue - Carry;
+
+ /* Update the flags */
+ 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 + Carry) & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+
+ return TRUE;
+
+}
+
+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;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xED) == 0x28);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+ else if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!Soft386ReadModrmByteOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
+ && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xED) == 0x29);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the address size */
+ AddressSize = !AddressSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_OPSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check the operand size */
+ if (OperandSize)
+ {
+ ULONG FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+ }
+ else
+ {
+ USHORT FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
+{
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xEF) == 0x2C);
+
+ if (State->PrefixFlags)
+ {
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
+ && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xEF) == 0x2D);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
+ }
+ else
+ {
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
+
+ if (!Soft386FetchWord(State, &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Carry = State->Flags.Cf;
+
+ /* Clear the carry flag */
+ State->Flags.Cf = FALSE;
+
+ /* Check if the first BCD digit is invalid or there was a borrow */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
+ {
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
+ if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
+ {
+ /* A borrow occurred */
+ State->Flags.Cf = TRUE;
+ }
+
+ /* 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(Soft386OpcodeAaa)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+ /*
+ * 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++;
+
+ /* 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(Soft386OpcodeAas)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+ /*
+ * 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(Soft386OpcodePushAll)
+{
+ 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 == 0x60);
+
+ 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;
+ }
+
+ /* Push all the registers in order */
+ for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
+ {
+ 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;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
+{
+ INT i;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Value;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x61);
+
+ 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;
+ }
+
+ /* Pop all the registers in reverse order */
+ for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
+ {
+ /* Pop the value */
+ if (!Soft386StackPop(State, &Value))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Don't modify ESP */
+ if (i != SOFT386_REG_ESP)
+ {
+ if (Size) State->GeneralRegs[i].Long = Value;
+ else State->GeneralRegs[i].LowWord = LOWORD(Value);
+ }
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
+{
+ USHORT FirstValue, SecondValue;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+ || State->Flags.Vm
+ || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
+ {
+ /* Cannot be used in real mode or with a LOCK prefix */
+ 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))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if the RPL needs adjusting */
+ if ((SecondValue & 3) < (FirstValue & 3))
+ {
+ /* 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
+ {
+ /* Clear ZF */
+ State->Flags.Zf = FALSE;
+ return TRUE;
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x68);
+
+ 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;
+
+ if (!Soft386FetchDword(State, &Data))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
+ }
+ else
+ {
+ USHORT Data;
+
+ if (!Soft386FetchWord(State, &Data))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
+{
+ BOOLEAN OperandSize, AddressSize;
+ SOFT386_MOD_REG_RM ModRegRm;
+ LONG Multiplier;
+ LONGLONG Product;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x69);
+
+ 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;
+ }
+
+ /* Fetch the parameters */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (Opcode == 0x6B)
+ {
+ CHAR Byte;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchByte(State, (PUCHAR)&Byte))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = (LONG)Byte;
+ }
+ else
+ {
+ if (OperandSize)
+ {
+ LONG Dword;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchDword(State, (PULONG)&Dword))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = Dword;
+ }
+ else
+ {
+ SHORT Word;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchWord(State, (PUSHORT)&Word))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = (LONG)Word;
+ }
+ }
+
+ if (OperandSize)
+ {
+ LONG RegValue, Multiplicand;
+
+ /* Read the operands */
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ (PULONG)&RegValue,
+ (PULONG)&Multiplicand))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Multiply */
+ Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+ }
+ else
+ {
+ SHORT RegValue, Multiplicand;
+
+ /* Read the operands */
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ (PUSHORT)&RegValue,
+ (PUSHORT)&Multiplicand))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Multiply */
+ Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+ }
+
+ /* 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;
+
+ /* Write-back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ TRUE,
+ (ULONG)((LONG)Product));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
+{
+ UCHAR Data;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x6A);
+
+ if (!Soft386FetchByte(State, &Data))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
+{
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x88);
+
+ 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)
+{
+ USHORT Segment = 0;
+ ULONG Offset = 0;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xEA);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Fetch the offset */
+ if (Size)
+ {
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+
+ /* Fetch the segment */
+ if (!Soft386FetchWord(State, &Segment))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Load the new CS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, Segment))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Load new (E)IP */
+ if (Size) State->InstPtr.Long = Offset;
+ else State->InstPtr.LowWord = LOWORD(Offset);
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
+{
+ 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;
+ }
+
+ /* 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;
+
+ 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(Soft386OpcodeMovOffsetAl)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Offset;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA2);
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ if (Size)
+ {
+ ULONG Offset;
+
+ 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
+ {
+ USHORT Offset;
+
+ if (!Soft386FetchWord(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].LowWord,
+ sizeof(USHORT));
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSalc)
+{
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xD6);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Set all the bits of AL to CF */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
+{
+ ULONG Data, DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xA4);
+
+ 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 == 0xA4) 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;
+
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytesSrc = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_ESI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_ESI].LowWord);
+ ULONG MaxBytesDest = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+
+ Processed = min(Processed, min(MaxBytesSrc, MaxBytesDest) / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ if (State->Flags.Df)
+ {
+ /* Reduce ESI and EDI by the number of bytes to transfer */
+ if (AddressSize)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long -= Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord -= Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+ }
+ }
+
+ /* Read from memory */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase ESI and EDI by the number of bytes transfered */
+ if (AddressSize)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long += Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord += Processed * DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
+ }
+ else
+ {
+ /* 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(Soft386OpcodeCmps)
+{
+ ULONG FirstValue = 0, SecondValue = 0, Result;
+ ULONG DataSize, DataMask, SignFlag;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 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;
+ }
+ }
+
+ // FIXME: This method is slow!
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ BOOLEAN Repeat = TRUE;
+
+ if (OperandSize)
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0)
+ {
+ /* ECX is 0 */
+ Repeat = FALSE;
+ }
+ }
+ else
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0)
+ {
+ /* CX is 0 */
+ Repeat = FALSE;
+ }
+ }
+
+ if (((State->PrefixFlags & SOFT386_PREFIX_REP) && !State->Flags.Zf)
+ || ((State->PrefixFlags & SOFT386_PREFIX_REPNZ) && State->Flags.Zf))
+ {
+ /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
+ Repeat = FALSE;
+ }
+
+ if (Repeat)
+ {
+ /* Repeat the instruction */
+ State->InstPtr = State->SavedInstPtr;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
+{
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xAA);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* 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);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ if (State->Flags.Df)
+ {
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
+ }
+ else
+ {
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
+{
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xAC);
+
+ 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 == 0xAC) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
+ {
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
+
+ /* If the count is 0, do nothing */
+ if (Count == 0) return TRUE;
+
+ /* Only the last entry will be loaded */
+ if (!State->Flags.Df)
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long += (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord += (Count - 1) * DataSize;
+ }
+ else
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long -= (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= (Count - 1) * DataSize;
+ }
+ }
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* 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(Soft386OpcodeScas)
+{
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue = 0;
+ ULONG Result;
+ ULONG DataSize, DataMask, SignFlag;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xAE);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* Calculate the size */
+ if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ /* Calculate the mask and sign flag */
+ DataMask = (1 << (DataSize * 8)) - 1;
+ SignFlag = 1 << ((DataSize * 8) - 1);
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ &SecondValue,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Calculate the result */
+ FirstValue &= DataMask;
+ SecondValue &= DataMask;
+ Result = (FirstValue - SecondValue) & DataMask;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
+ && ((FirstValue & SignFlag) != (Result & SignFlag));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
+
+ // FIXME: This method is slow!
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ BOOLEAN Repeat = TRUE;
+
+ if (OperandSize)
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0)
+ {
+ /* ECX is 0 */
+ Repeat = FALSE;
+ }
+ }
+ else
+ {
+ if ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0)
+ {
+ /* CX is 0 */
+ Repeat = FALSE;
+ }
+ }
+
+ if (((State->PrefixFlags & SOFT386_PREFIX_REP) && !State->Flags.Zf)
+ || ((State->PrefixFlags & SOFT386_PREFIX_REPNZ) && State->Flags.Zf))
+ {
+ /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
+ Repeat = FALSE;
+ }
+
+ if (Repeat)
+ {
+ /* Repeat the instruction */
+ State->InstPtr = State->SavedInstPtr;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
+{
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0x6C);
+
+ 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 == 0x6C) 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;
+
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
+
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
+
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
+ }
+ else
+ {
+ ULONG Data = 0;
+
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &Data,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
+{
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0x6E);
+
+ 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 == 0x6E) 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;
+
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
+ {
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
+ if (!AddressSize)
+ {
+ ULONG MaxBytes = State->Flags.Df
+ ? (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord
+ : (0x10000 - (ULONG)State->GeneralRegs[SOFT386_REG_EDI].LowWord);
+
+ Processed = min(Processed, MaxBytes / DataSize);
+ if (Processed == 0) Processed = 1;
+ }
+
+ /* Read from memory */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
+
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
+
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
+ }
+
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
+ }
+ else
+ {
+ ULONG Data = 0;
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &Data,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Increment/decrement ESI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}