/****************************************************************************
*
* Realmode X86 Emulator Library
*
* Copyright (C) 1996-1999 SciTech Software, Inc.
* Copyright (C) David Mosberger-Tang
* Copyright (C) 1999 Egbert Eich
* Copyright (C) 2007 Joerg Sonnenberger
*
* ========================================================================
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of the authors not be used
* in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The authors makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
*
* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
****************************************************************************/
if (emu->x86.intr & INTR_SYNCH) {
intno = emu->x86.intno;
emu->x86.intr = 0;
x86emu_intr_dispatch(emu, intno);
}
}
/****************************************************************************
PARAMETERS:
intrnum - Interrupt number to raise
REMARKS:
Raise the specified interrupt to be handled before the execution of the
next instruction.
****************************************************************************/
void
x86emu_intr_raise(struct X86EMU *emu, uint8_t intrnum)
{
emu->x86.intno = intrnum;
emu->x86.intr |= INTR_SYNCH;
}
/****************************************************************************
REMARKS:
Main execution loop for the emulator. We return from here when the system
halts, which is normally caused by a stack fault when we return from the
original real mode call.
****************************************************************************/
void
X86EMU_exec(struct X86EMU *emu)
{
emu->x86.intr = 0;
#ifdef _KERNEL
if (setjmp(&emu->exec_state))
return;
#else
if (setjmp(emu->exec_state))
return;
#endif
for (;;) {
if (emu->x86.intr) {
if (((emu->x86.intr & INTR_SYNCH) && (emu->x86.intno == 0 || emu->x86.intno == 2)) ||
!ACCESS_FLAG(F_IF)) {
x86emu_intr_handle(emu);
}
}
if (emu->x86.R_CS == 0 && emu->x86.R_IP == 0)
return;
X86EMU_exec_one_byte(emu);
++emu->cur_cycles;
}
}
X86EMU_exec(emu);
}
/****************************************************************************
REMARKS:
Halts the system by setting the halted system flag.
****************************************************************************/
void
X86EMU_halt_sys(struct X86EMU *emu)
{
#ifdef _KERNEL
longjmp(&emu->exec_state);
#else
longjmp(emu->exec_state, 1);
#endif
}
/****************************************************************************
PARAMETERS:
mod - Mod value from decoded byte
regh - Reg h value from decoded byte
regl - Reg l value from decoded byte
REMARKS:
Raise the specified interrupt to be handled before the execution of the
next instruction.
NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
****************************************************************************/
static void
fetch_decode_modrm(struct X86EMU *emu)
{
int fetched;
REMARKS:
This function returns the immediate byte from the instruction queue, and
moves the instruction pointer to the next value.
NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
****************************************************************************/
static uint8_t
fetch_byte_imm(struct X86EMU *emu)
{
uint8_t fetched;
fetched = fetch_byte(emu, emu->x86.R_CS, emu->x86.R_IP);
emu->x86.R_IP++;
return fetched;
}
/****************************************************************************
RETURNS:
Immediate word value read from instruction queue
REMARKS:
This function returns the immediate byte from the instruction queue, and
moves the instruction pointer to the next value.
NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
****************************************************************************/
static uint16_t
fetch_word_imm(struct X86EMU *emu)
{
uint16_t fetched;
fetched = fetch_word(emu, emu->x86.R_CS, emu->x86.R_IP);
emu->x86.R_IP += 2;
return fetched;
}
/****************************************************************************
RETURNS:
Immediate lone value read from instruction queue
REMARKS:
This function returns the immediate byte from the instruction queue, and
moves the instruction pointer to the next value.
NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
****************************************************************************/
static uint32_t
fetch_long_imm(struct X86EMU *emu)
{
uint32_t fetched;
fetched = fetch_long(emu, emu->x86.R_CS, emu->x86.R_IP);
emu->x86.R_IP += 4;
return fetched;
}
/****************************************************************************
RETURNS:
Value of the default data segment
REMARKS:
Inline function that returns the default data segment for the current
instruction.
On the x86 processor, the default segment is not always DS if there is
no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
addresses relative to SS (ie: on the stack). So, at the minimum, all
decodings of addressing modes would have to set/clear a bit describing
whether the access is relative to DS or SS. That is the function of the
cpu-state-variable emu->x86.mode. There are several potential states:
repe prefix seen (handled elsewhere)
repne prefix seen (ditto)
cs segment override
ds segment override
es segment override
fs segment override
gs segment override
ss segment override
ds/ss select (in absence of override)
Each of the above 7 items are handled with a bit in the mode field.
****************************************************************************/
static uint32_t
get_data_segment(struct X86EMU *emu)
{
switch (emu->x86.mode & SYSMODE_SEGMASK) {
case 0: /* default case: use ds register */
case SYSMODE_SEGOVR_DS:
case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
return emu->x86.R_DS;
case SYSMODE_SEG_DS_SS:/* non-overridden, use ss register */
return emu->x86.R_SS;
case SYSMODE_SEGOVR_CS:
case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
return emu->x86.R_CS;
case SYSMODE_SEGOVR_ES:
case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
return emu->x86.R_ES;
case SYSMODE_SEGOVR_FS:
case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
return emu->x86.R_FS;
case SYSMODE_SEGOVR_GS:
case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
return emu->x86.R_GS;
case SYSMODE_SEGOVR_SS:
case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
return emu->x86.R_SS;
}
X86EMU_halt_sys(emu);
}
/****************************************************************************
PARAMETERS:
offset - Offset to load data from
RETURNS:
Byte value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint8_t
fetch_data_byte(struct X86EMU *emu, uint32_t offset)
{
return fetch_byte(emu, get_data_segment(emu), offset);
}
/****************************************************************************
PARAMETERS:
offset - Offset to load data from
RETURNS:
Word value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint16_t
fetch_data_word(struct X86EMU *emu, uint32_t offset)
{
return fetch_word(emu, get_data_segment(emu), offset);
}
/****************************************************************************
PARAMETERS:
offset - Offset to load data from
RETURNS:
Long value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint32_t
fetch_data_long(struct X86EMU *emu, uint32_t offset)
{
return fetch_long(emu, get_data_segment(emu), offset);
}
/****************************************************************************
PARAMETERS:
segment - Segment to load data from
offset - Offset to load data from
RETURNS:
Byte value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint8_t
fetch_byte(struct X86EMU *emu, uint32_t segment, uint32_t offset)
{
return (*emu->emu_rdb) (emu, ((uint32_t) segment << 4) + offset);
}
/****************************************************************************
PARAMETERS:
segment - Segment to load data from
offset - Offset to load data from
RETURNS:
Word value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint16_t
fetch_word(struct X86EMU *emu, uint32_t segment, uint32_t offset)
{
return (*emu->emu_rdw) (emu, ((uint32_t) segment << 4) + offset);
}
/****************************************************************************
PARAMETERS:
segment - Segment to load data from
offset - Offset to load data from
RETURNS:
Long value read from the absolute memory location.
NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint32_t
fetch_long(struct X86EMU *emu, uint32_t segment, uint32_t offset)
{
return (*emu->emu_rdl) (emu, ((uint32_t) segment << 4) + offset);
}
/****************************************************************************
PARAMETERS:
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a word value to an segmented memory location. The segment used is
the current 'default' segment, which may have been overridden.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_data_byte(struct X86EMU *emu, uint32_t offset, uint8_t val)
{
store_byte(emu, get_data_segment(emu), offset, val);
}
/****************************************************************************
PARAMETERS:
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a word value to an segmented memory location. The segment used is
the current 'default' segment, which may have been overridden.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_data_word(struct X86EMU *emu, uint32_t offset, uint16_t val)
{
store_word(emu, get_data_segment(emu), offset, val);
}
/****************************************************************************
PARAMETERS:
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a long value to an segmented memory location. The segment used is
the current 'default' segment, which may have been overridden.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_data_long(struct X86EMU *emu, uint32_t offset, uint32_t val)
{
store_long(emu, get_data_segment(emu), offset, val);
}
/****************************************************************************
PARAMETERS:
segment - Segment to store data at
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a byte value to an absolute memory location.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_byte(struct X86EMU *emu, uint32_t segment, uint32_t offset, uint8_t val)
{
(*emu->emu_wrb) (emu, ((uint32_t) segment << 4) + offset, val);
}
/****************************************************************************
PARAMETERS:
segment - Segment to store data at
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a word value to an absolute memory location.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_word(struct X86EMU *emu, uint32_t segment, uint32_t offset, uint16_t val)
{
(*emu->emu_wrw) (emu, ((uint32_t) segment << 4) + offset, val);
}
/****************************************************************************
PARAMETERS:
segment - Segment to store data at
offset - Offset to store data at
val - Value to store
REMARKS:
Writes a long value to an absolute memory location.
NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
store_long(struct X86EMU *emu, uint32_t segment, uint32_t offset, uint32_t val)
{
(*emu->emu_wrl) (emu, ((uint32_t) segment << 4) + offset, val);
}
/****************************************************************************
PARAMETERS:
reg - Register to decode
RETURNS:
Pointer to the appropriate register
REMARKS:
Return a pointer to the register given by the R/RM field of the
modrm byte, for byte operands. Also enables the decoding of instructions.
****************************************************************************/
static uint8_t *
decode_rm_byte_register(struct X86EMU *emu, int reg)
{
switch (reg) {
case 0:
return &emu->x86.R_AL;
case 1:
return &emu->x86.R_CL;
case 2:
return &emu->x86.R_DL;
case 3:
return &emu->x86.R_BL;
case 4:
return &emu->x86.R_AH;
case 5:
return &emu->x86.R_CH;
case 6:
return &emu->x86.R_DH;
case 7:
return &emu->x86.R_BH;
default:
X86EMU_halt_sys(emu);
}
}
REMARKS:
Return a pointer to the register given by the R/RM field of the
modrm byte, for word operands. Also enables the decoding of instructions.
****************************************************************************/
static uint16_t *
decode_rm_word_register(struct X86EMU *emu, int reg)
{
switch (reg) {
case 0:
return &emu->x86.R_AX;
case 1:
return &emu->x86.R_CX;
case 2:
return &emu->x86.R_DX;
case 3:
return &emu->x86.R_BX;
case 4:
return &emu->x86.R_SP;
case 5:
return &emu->x86.R_BP;
case 6:
return &emu->x86.R_SI;
case 7:
return &emu->x86.R_DI;
default:
X86EMU_halt_sys(emu);
}
}
REMARKS:
Return a pointer to the register given by the R/RM field of the
modrm byte, for dword operands. Also enables the decoding of instructions.
****************************************************************************/
static uint32_t *
decode_rm_long_register(struct X86EMU *emu, int reg)
{
switch (reg) {
case 0:
return &emu->x86.R_EAX;
case 1:
return &emu->x86.R_ECX;
case 2:
return &emu->x86.R_EDX;
case 3:
return &emu->x86.R_EBX;
case 4:
return &emu->x86.R_ESP;
case 5:
return &emu->x86.R_EBP;
case 6:
return &emu->x86.R_ESI;
case 7:
return &emu->x86.R_EDI;
default:
X86EMU_halt_sys(emu);
}
}
/****************************************************************************
PARAMETERS:
reg - Register to decode
RETURNS:
Pointer to the appropriate register
REMARKS:
Return a pointer to the register given by the R/RM field of the
modrm byte, for word operands, modified from above for the weirdo
special case of segreg operands. Also enables the decoding of instructions.
****************************************************************************/
static uint16_t *
decode_rh_seg_register(struct X86EMU *emu)
{
switch (emu->cur_rh) {
case 0:
return &emu->x86.R_ES;
case 1:
return &emu->x86.R_CS;
case 2:
return &emu->x86.R_SS;
case 3:
return &emu->x86.R_DS;
case 4:
return &emu->x86.R_FS;
case 5:
return &emu->x86.R_GS;
default:
X86EMU_halt_sys(emu);
}
}
/*
*
* return offset from the SIB Byte
*/
static uint32_t
decode_sib_address(struct X86EMU *emu, int sib, int mod)
{
uint32_t base = 0, i = 0, scale = 1;
switch (sib & 0x07) {
case 0:
base = emu->x86.R_EAX;
break;
case 1:
base = emu->x86.R_ECX;
break;
case 2:
base = emu->x86.R_EDX;
break;
case 3:
base = emu->x86.R_EBX;
break;
case 4:
base = emu->x86.R_ESP;
emu->x86.mode |= SYSMODE_SEG_DS_SS;
break;
case 5:
if (mod == 0) {
base = fetch_long_imm(emu);
} else {
base = emu->x86.R_EBP;
emu->x86.mode |= SYSMODE_SEG_DS_SS;
}
break;
case 6:
base = emu->x86.R_ESI;
break;
case 7:
base = emu->x86.R_EDI;
break;
}
switch ((sib >> 3) & 0x07) {
case 0:
i = emu->x86.R_EAX;
break;
case 1:
i = emu->x86.R_ECX;
break;
case 2:
i = emu->x86.R_EDX;
break;
case 3:
i = emu->x86.R_EBX;
break;
case 4:
i = 0;
break;
case 5:
i = emu->x86.R_EBP;
break;
case 6:
i = emu->x86.R_ESI;
break;
case 7:
i = emu->x86.R_EDI;
break;
}
scale = 1 << ((sib >> 6) & 0x03);
return base + (i * scale);
}
/****************************************************************************
PARAMETERS:
rm - RM value to decode
RETURNS:
Offset in memory for the address decoding
REMARKS:
Return the offset given by mod=00, mod=01 or mod=10 addressing.
Also enables the decoding of instructions.
****************************************************************************/
static uint32_t
decode_rl_address(struct X86EMU *emu)
{
if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
uint32_t offset, sib;
/* 32-bit addressing */
switch (emu->cur_rl) {
case 0:
offset = emu->x86.R_EAX;
break;
case 1:
offset = emu->x86.R_ECX;
break;
case 2:
offset = emu->x86.R_EDX;
break;
case 3:
offset = emu->x86.R_EBX;
break;
case 4:
sib = fetch_byte_imm(emu);
offset = decode_sib_address(emu, sib, 0);
break;
case 5:
if (emu->cur_mod == 0) {
offset = fetch_long_imm(emu);
} else {
emu->x86.mode |= SYSMODE_SEG_DS_SS;
offset = emu->x86.R_EBP;
}
break;
case 6:
offset = emu->x86.R_ESI;
break;
case 7:
offset = emu->x86.R_EDI;
break;
default:
X86EMU_halt_sys(emu);
}
if (emu->cur_mod == 1)
offset += (int8_t)fetch_byte_imm(emu);
else if (emu->cur_mod == 2)
offset += fetch_long_imm(emu);
return offset;
} else {
uint16_t offset;
/* 16-bit addressing */
switch (emu->cur_rl) {
case 0:
offset = emu->x86.R_BX + emu->x86.R_SI;
break;
case 1:
offset = emu->x86.R_BX + emu->x86.R_DI;
break;
case 2:
emu->x86.mode |= SYSMODE_SEG_DS_SS;
offset = emu->x86.R_BP + emu->x86.R_SI;
break;
case 3:
emu->x86.mode |= SYSMODE_SEG_DS_SS;
offset = emu->x86.R_BP + emu->x86.R_DI;
break;
case 4:
offset = emu->x86.R_SI;
break;
case 5:
offset = emu->x86.R_DI;
break;
case 6:
if (emu->cur_mod == 0) {
offset = fetch_word_imm(emu);
} else {
emu->x86.mode |= SYSMODE_SEG_DS_SS;
offset = emu->x86.R_BP;
}
break;
case 7:
offset = emu->x86.R_BX;
break;
default:
X86EMU_halt_sys(emu);
}
if (emu->cur_mod == 1)
offset += (int8_t)fetch_byte_imm(emu);
else if (emu->cur_mod == 2)
offset += fetch_word_imm(emu);
return offset;
}
}
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction
*/
fetch_decode_modrm(emu);
destval = decode_and_fetch_byte(emu);
imm = fetch_byte_imm(emu);
destval = (*opc80_byte_operation[emu->cur_rh]) (emu, destval, imm);
if (emu->cur_rh != 7)
write_back_byte(emu, destval);
}
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction
*/
fetch_decode_modrm(emu);
destval = decode_and_fetch_long(emu);
imm = fetch_long_imm(emu);
destval = (*opc81_long_operation[emu->cur_rh]) (emu, destval, imm);
if (emu->cur_rh != 7)
write_back_long(emu, destval);
}
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction
*/
fetch_decode_modrm(emu);
destval = decode_and_fetch_word(emu);
imm = fetch_word_imm(emu);
destval = (*opc81_word_operation[emu->cur_rh]) (emu, destval, imm);
if (emu->cur_rh != 7)
write_back_word(emu, destval);
}
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction Similar to opcode 81, except that
* the immediate byte is sign extended to a word length.
*/
fetch_decode_modrm(emu);
destval = decode_and_fetch_byte(emu);
imm = fetch_byte_imm(emu);
destval = (*opc82_byte_operation[emu->cur_rh]) (emu, destval, imm);
if (emu->cur_rh != 7)
write_back_byte(emu, destval);
}
fetch_decode_modrm(emu);
destreg = decode_rh_seg_register(emu);
*destreg = decode_and_fetch_word(emu);
/*
* Clean up, and reset all the R_xSP pointers to the correct
* locations. This is about 3x too much overhead (doing all the
* segreg ptrs when only one is needed, but this instruction
* *cannot* be that common, and this isn't too much work anyway.
*/
}
/****************************************************************************
REMARKS:
Handles opcode 0x8f
****************************************************************************/
static void
x86emuOp32_pop_RM(struct X86EMU *emu)
{
uint32_t destoffset;
uint32_t destval, *destreg;
/*
* Yet another weirdo special case instruction format. Part of
* the opcode held below in "RH". Doubly nested case would
* result, except that the decoded instruction
*/
fetch_decode_modrm(emu);
/* know operation, decode the mod byte to find the addressing mode. */
destval = decode_and_fetch_byte_imm8(emu, &amt);
destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, amt);
write_back_byte(emu, destval);
}
/* used by opcodes c1, d1, and d3. */
static
uint16_t(* const opcD1_word_operation[]) (struct X86EMU *, uint16_t s, uint8_t d) =
{
rol_word,
ror_word,
rcl_word,
rcr_word,
shl_word,
shr_word,
shl_word, /* sal_byte === shl_byte by definition */
sar_word,
};
/* used by opcodes c1, d1, and d3. */
static
uint32_t(* const opcD1_long_operation[]) (struct X86EMU *, uint32_t s, uint8_t d) =
{
rol_long,
ror_long,
rcl_long,
rcr_long,
shl_long,
shr_long,
shl_long, /* sal_byte === shl_byte by definition */
sar_long,
};
/****************************************************************************
REMARKS:
Handles opcode 0xc1
****************************************************************************/
static void
x86emuOp_opcC1_word_RM_MEM(struct X86EMU *emu)
{
uint8_t amt;
/*
* Yet another weirdo special case instruction format. Part of
* the opcode held below in "RH". Doubly nested case would
* result, except that the decoded instruction
*/
fetch_decode_modrm(emu);
if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
uint32_t destval;
a = fetch_byte_imm(emu); /* this is a stupid encoding. */
if (a != 10) {
/* fix: add base decoding aam_word(uint8_t val, int base a) */
X86EMU_halt_sys(emu);
}
/* note the type change here --- returning AL and AH in AX. */
emu->x86.R_AX = aam_word(emu, emu->x86.R_AL);
}
/****************************************************************************
REMARKS:
Handles opcode 0xd5
****************************************************************************/
static void
x86emuOp_aad(struct X86EMU *emu)
{
uint8_t a;
a = fetch_byte_imm(emu);
if (a != 10) {
/* fix: add base decoding aad_word(uint16_t val, int base a) */
X86EMU_halt_sys(emu);
}
emu->x86.R_AX = aad_word(emu, emu->x86.R_AX);
}
/* opcode 0xd6 ILLEGAL OPCODE */
switch (op1) {
case 0x00:
common_binop_byte_rm_r(emu, add_byte);
break;
case 0x01:
common_binop_word_long_rm_r(emu, add_word, add_long);
break;
case 0x02:
common_binop_byte_r_rm(emu, add_byte);
break;
case 0x03:
common_binop_word_long_r_rm(emu, add_word, add_long);
break;
case 0x04:
common_binop_byte_imm(emu, add_byte);
break;
case 0x05:
common_binop_word_long_imm(emu, add_word, add_long);
break;
case 0x06:
push_word(emu, emu->x86.R_ES);
break;
case 0x07:
emu->x86.R_ES = pop_word(emu);
break;
case 0x08:
common_binop_byte_rm_r(emu, or_byte);
break;
case 0x09:
common_binop_word_long_rm_r(emu, or_word, or_long);
break;
case 0x0a:
common_binop_byte_r_rm(emu, or_byte);
break;
case 0x0b:
common_binop_word_long_r_rm(emu, or_word, or_long);
break;
case 0x0c:
common_binop_byte_imm(emu, or_byte);
break;
case 0x0d:
common_binop_word_long_imm(emu, or_word, or_long);
break;
case 0x0e:
push_word(emu, emu->x86.R_CS);
break;
case 0x0f:
X86EMU_exec_two_byte(emu);
break;
case 0x10:
common_binop_byte_rm_r(emu, adc_byte);
break;
case 0x11:
common_binop_word_long_rm_r(emu, adc_word, adc_long);
break;
case 0x12:
common_binop_byte_r_rm(emu, adc_byte);
break;
case 0x13:
common_binop_word_long_r_rm(emu, adc_word, adc_long);
break;
case 0x14:
common_binop_byte_imm(emu, adc_byte);
break;
case 0x15:
common_binop_word_long_imm(emu, adc_word, adc_long);
break;
case 0x16:
push_word(emu, emu->x86.R_SS);
break;
case 0x17:
emu->x86.R_SS = pop_word(emu);
break;
case 0x18:
common_binop_byte_rm_r(emu, sbb_byte);
break;
case 0x19:
common_binop_word_long_rm_r(emu, sbb_word, sbb_long);
break;
case 0x1a:
common_binop_byte_r_rm(emu, sbb_byte);
break;
case 0x1b:
common_binop_word_long_r_rm(emu, sbb_word, sbb_long);
break;
case 0x1c:
common_binop_byte_imm(emu, sbb_byte);
break;
case 0x1d:
common_binop_word_long_imm(emu, sbb_word, sbb_long);
break;
case 0x1e:
push_word(emu, emu->x86.R_DS);
break;
case 0x1f:
emu->x86.R_DS = pop_word(emu);
break;
case 0x20:
common_binop_byte_rm_r(emu, and_byte);
break;
case 0x21:
common_binop_word_long_rm_r(emu, and_word, and_long);
break;
case 0x22:
common_binop_byte_r_rm(emu, and_byte);
break;
case 0x23:
common_binop_word_long_r_rm(emu, and_word, and_long);
break;
case 0x24:
common_binop_byte_imm(emu, and_byte);
break;
case 0x25:
common_binop_word_long_imm(emu, and_word, and_long);
break;
case 0x26:
emu->x86.mode |= SYSMODE_SEGOVR_ES;
break;
case 0x27:
emu->x86.R_AL = daa_byte(emu, emu->x86.R_AL);
break;
case 0x28:
common_binop_byte_rm_r(emu, sub_byte);
break;
case 0x29:
common_binop_word_long_rm_r(emu, sub_word, sub_long);
break;
case 0x2a:
common_binop_byte_r_rm(emu, sub_byte);
break;
case 0x2b:
common_binop_word_long_r_rm(emu, sub_word, sub_long);
break;
case 0x2c:
common_binop_byte_imm(emu, sub_byte);
break;
case 0x2d:
common_binop_word_long_imm(emu, sub_word, sub_long);
break;
case 0x2e:
emu->x86.mode |= SYSMODE_SEGOVR_CS;
break;
case 0x2f:
emu->x86.R_AL = das_byte(emu, emu->x86.R_AL);
break;
case 0x30:
common_binop_byte_rm_r(emu, xor_byte);
break;
case 0x31:
common_binop_word_long_rm_r(emu, xor_word, xor_long);
break;
case 0x32:
common_binop_byte_r_rm(emu, xor_byte);
break;
case 0x33:
common_binop_word_long_r_rm(emu, xor_word, xor_long);
break;
case 0x34:
common_binop_byte_imm(emu, xor_byte);
break;
case 0x35:
common_binop_word_long_imm(emu, xor_word, xor_long);
break;
case 0x36:
emu->x86.mode |= SYSMODE_SEGOVR_SS;
break;
case 0x37:
emu->x86.R_AX = aaa_word(emu, emu->x86.R_AX);
break;
case 0x38:
common_binop_ns_byte_rm_r(emu, cmp_byte_no_return);
break;
case 0x39:
common_binop_ns_word_long_rm_r(emu, cmp_word_no_return,
cmp_long_no_return);
break;
case 0x3a:
x86emuOp_cmp_byte_R_RM(emu);
break;
case 0x3b:
x86emuOp_cmp_word_R_RM(emu);
break;
case 0x3c:
x86emuOp_cmp_byte_AL_IMM(emu);
break;
case 0x3d:
x86emuOp_cmp_word_AX_IMM(emu);
break;
case 0x3e:
emu->x86.mode |= SYSMODE_SEGOVR_DS;
break;
case 0x3f:
emu->x86.R_AX = aas_word(emu, emu->x86.R_AX);
break;
case 0x40:
common_inc_word_long(emu, &emu->x86.register_a);
break;
case 0x41:
common_inc_word_long(emu, &emu->x86.register_c);
break;
case 0x42:
common_inc_word_long(emu, &emu->x86.register_d);
break;
case 0x43:
common_inc_word_long(emu, &emu->x86.register_b);
break;
case 0x44:
common_inc_word_long(emu, &emu->x86.register_sp);
break;
case 0x45:
common_inc_word_long(emu, &emu->x86.register_bp);
break;
case 0x46:
common_inc_word_long(emu, &emu->x86.register_si);
break;
case 0x47:
common_inc_word_long(emu, &emu->x86.register_di);
break;
case 0x48:
common_dec_word_long(emu, &emu->x86.register_a);
break;
case 0x49:
common_dec_word_long(emu, &emu->x86.register_c);
break;
case 0x4a:
common_dec_word_long(emu, &emu->x86.register_d);
break;
case 0x4b:
common_dec_word_long(emu, &emu->x86.register_b);
break;
case 0x4c:
common_dec_word_long(emu, &emu->x86.register_sp);
break;
case 0x4d:
common_dec_word_long(emu, &emu->x86.register_bp);
break;
case 0x4e:
common_dec_word_long(emu, &emu->x86.register_si);
break;
case 0x4f:
common_dec_word_long(emu, &emu->x86.register_di);
break;
case 0x50:
common_push_word_long(emu, &emu->x86.register_a);
break;
case 0x51:
common_push_word_long(emu, &emu->x86.register_c);
break;
case 0x52:
common_push_word_long(emu, &emu->x86.register_d);
break;
case 0x53:
common_push_word_long(emu, &emu->x86.register_b);
break;
case 0x54:
common_push_word_long(emu, &emu->x86.register_sp);
break;
case 0x55:
common_push_word_long(emu, &emu->x86.register_bp);
break;
case 0x56:
common_push_word_long(emu, &emu->x86.register_si);
break;
case 0x57:
common_push_word_long(emu, &emu->x86.register_di);
break;
case 0x58:
common_pop_word_long(emu, &emu->x86.register_a);
break;
case 0x59:
common_pop_word_long(emu, &emu->x86.register_c);
break;
case 0x5a:
common_pop_word_long(emu, &emu->x86.register_d);
break;
case 0x5b:
common_pop_word_long(emu, &emu->x86.register_b);
break;
case 0x5c:
common_pop_word_long(emu, &emu->x86.register_sp);
break;
case 0x5d:
common_pop_word_long(emu, &emu->x86.register_bp);
break;
case 0x5e:
common_pop_word_long(emu, &emu->x86.register_si);
break;
case 0x5f:
common_pop_word_long(emu, &emu->x86.register_di);
break;
case 0x60:
x86emuOp_push_all(emu);
break;
case 0x61:
x86emuOp_pop_all(emu);
break;
/* 0x62 bound */
/* 0x63 arpl */
case 0x64:
emu->x86.mode |= SYSMODE_SEGOVR_FS;
break;
case 0x65:
emu->x86.mode |= SYSMODE_SEGOVR_GS;
break;
case 0x66:
emu->x86.mode |= SYSMODE_PREFIX_DATA;
break;
case 0x67:
emu->x86.mode |= SYSMODE_PREFIX_ADDR;
break;
case 0x68:
x86emuOp_push_word_IMM(emu);
break;
case 0x69:
common_imul_imm(emu, false);
break;
case 0x6a:
x86emuOp_push_byte_IMM(emu);
break;
case 0x6b:
common_imul_imm(emu, true);
break;
case 0x6c:
ins(emu, 1);
break;
case 0x6d:
x86emuOp_ins_word(emu);
break;
case 0x6e:
outs(emu, 1);
break;
case 0x6f:
x86emuOp_outs_word(emu);
break;
case 0x70:
common_jmp_near(emu, ACCESS_FLAG(F_OF));
break;
case 0x71:
common_jmp_near(emu, !ACCESS_FLAG(F_OF));
break;
case 0x72:
common_jmp_near(emu, ACCESS_FLAG(F_CF));
break;
case 0x73:
common_jmp_near(emu, !ACCESS_FLAG(F_CF));
break;
case 0x74:
common_jmp_near(emu, ACCESS_FLAG(F_ZF));
break;
case 0x75:
common_jmp_near(emu, !ACCESS_FLAG(F_ZF));
break;
case 0x76:
common_jmp_near(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
break;
case 0x77:
common_jmp_near(emu, !ACCESS_FLAG(F_CF) && !ACCESS_FLAG(F_ZF));
break;
case 0x78:
common_jmp_near(emu, ACCESS_FLAG(F_SF));
break;
case 0x79:
common_jmp_near(emu, !ACCESS_FLAG(F_SF));
break;
case 0x7a:
common_jmp_near(emu, ACCESS_FLAG(F_PF));
break;
case 0x7b:
common_jmp_near(emu, !ACCESS_FLAG(F_PF));
break;
case 0x7c:
x86emuOp_jump_near_L(emu);
break;
case 0x7d:
x86emuOp_jump_near_NL(emu);
break;
case 0x7e:
x86emuOp_jump_near_LE(emu);
break;
case 0x7f:
x86emuOp_jump_near_NLE(emu);
break;
case 0x80:
x86emuOp_opc80_byte_RM_IMM(emu);
break;
case 0x81:
x86emuOp_opc81_word_RM_IMM(emu);
break;
case 0x82:
x86emuOp_opc82_byte_RM_IMM(emu);
break;
case 0x83:
x86emuOp_opc83_word_RM_IMM(emu);
break;
case 0x84:
common_binop_ns_byte_rm_r(emu, test_byte);
break;
case 0x85:
common_binop_ns_word_long_rm_r(emu, test_word, test_long);
break;
case 0x86:
x86emuOp_xchg_byte_RM_R(emu);
break;
case 0x87:
x86emuOp_xchg_word_RM_R(emu);
break;
case 0x88:
x86emuOp_mov_byte_RM_R(emu);
break;
case 0x89:
x86emuOp_mov_word_RM_R(emu);
break;
case 0x8a:
x86emuOp_mov_byte_R_RM(emu);
break;
case 0x8b:
x86emuOp_mov_word_R_RM(emu);
break;
case 0x8c:
x86emuOp_mov_word_RM_SR(emu);
break;
case 0x8d:
x86emuOp_lea_word_R_M(emu);
break;
case 0x8e:
x86emuOp_mov_word_SR_RM(emu);
break;
case 0x8f:
x86emuOp_pop_RM(emu);
break;
case 0x90:
/* nop */
break;
case 0x91:
x86emuOp_xchg_word_AX_CX(emu);
break;
case 0x92:
x86emuOp_xchg_word_AX_DX(emu);
break;
case 0x93:
x86emuOp_xchg_word_AX_BX(emu);
break;
case 0x94:
x86emuOp_xchg_word_AX_SP(emu);
break;
case 0x95:
x86emuOp_xchg_word_AX_BP(emu);
break;
case 0x96:
x86emuOp_xchg_word_AX_SI(emu);
break;
case 0x97:
x86emuOp_xchg_word_AX_DI(emu);
break;
case 0x98:
x86emuOp_cbw(emu);
break;
case 0x99:
x86emuOp_cwd(emu);
break;
case 0x9a:
x86emuOp_call_far_IMM(emu);
break;
case 0x9b:
/* wait */
break;
case 0x9c:
x86emuOp_pushf_word(emu);
break;
case 0x9d:
x86emuOp_popf_word(emu);
break;
case 0x9e:
x86emuOp_sahf(emu);
break;
case 0x9f:
x86emuOp_lahf(emu);
break;
case 0xa0:
x86emuOp_mov_AL_M_IMM(emu);
break;
case 0xa1:
x86emuOp_mov_AX_M_IMM(emu);
break;
case 0xa2:
x86emuOp_mov_M_AL_IMM(emu);
break;
case 0xa3:
x86emuOp_mov_M_AX_IMM(emu);
break;
case 0xa4:
x86emuOp_movs_byte(emu);
break;
case 0xa5:
x86emuOp_movs_word(emu);
break;
case 0xa6:
x86emuOp_cmps_byte(emu);
break;
case 0xa7:
x86emuOp_cmps_word(emu);
break;
case 0xa8:
test_byte(emu, emu->x86.R_AL, fetch_byte_imm(emu));
break;
case 0xa9:
x86emuOp_test_AX_IMM(emu);
break;
case 0xaa:
x86emuOp_stos_byte(emu);
break;
case 0xab:
x86emuOp_stos_word(emu);
break;
case 0xac:
x86emuOp_lods_byte(emu);
break;
case 0xad:
x86emuOp_lods_word(emu);
break;
case 0xae:
x86emuOp_scas_byte(emu);
break;
case 0xaf:
x86emuOp_scas_word(emu);
break;
case 0xb0:
emu->x86.R_AL = fetch_byte_imm(emu);
break;
case 0xb1:
emu->x86.R_CL = fetch_byte_imm(emu);
break;
case 0xb2:
emu->x86.R_DL = fetch_byte_imm(emu);
break;
case 0xb3:
emu->x86.R_BL = fetch_byte_imm(emu);
break;
case 0xb4:
emu->x86.R_AH = fetch_byte_imm(emu);
break;
case 0xb5:
emu->x86.R_CH = fetch_byte_imm(emu);
break;
case 0xb6:
emu->x86.R_DH = fetch_byte_imm(emu);
break;
case 0xb7:
emu->x86.R_BH = fetch_byte_imm(emu);
break;
case 0xb8:
x86emuOp_mov_word_AX_IMM(emu);
break;
case 0xb9:
x86emuOp_mov_word_CX_IMM(emu);
break;
case 0xba:
x86emuOp_mov_word_DX_IMM(emu);
break;
case 0xbb:
x86emuOp_mov_word_BX_IMM(emu);
break;
case 0xbc:
x86emuOp_mov_word_SP_IMM(emu);
break;
case 0xbd:
x86emuOp_mov_word_BP_IMM(emu);
break;
case 0xbe:
x86emuOp_mov_word_SI_IMM(emu);
break;
case 0xbf:
x86emuOp_mov_word_DI_IMM(emu);
break;
case 0xc0:
x86emuOp_opcC0_byte_RM_MEM(emu);
break;
case 0xc1:
x86emuOp_opcC1_word_RM_MEM(emu);
break;
case 0xc2:
x86emuOp_ret_near_IMM(emu);
break;
case 0xc3:
emu->x86.R_IP = pop_word(emu);
break;
case 0xc4:
common_load_far_pointer(emu, &emu->x86.R_ES);
break;
case 0xc5:
common_load_far_pointer(emu, &emu->x86.R_DS);
break;
case 0xc6:
x86emuOp_mov_byte_RM_IMM(emu);
break;
case 0xc7:
x86emuOp_mov_word_RM_IMM(emu);
break;
case 0xc8:
x86emuOp_enter(emu);
break;
case 0xc9:
x86emuOp_leave(emu);
break;
case 0xca:
x86emuOp_ret_far_IMM(emu);
break;
case 0xcb:
x86emuOp_ret_far(emu);
break;
case 0xcc:
x86emuOp_int3(emu);
break;
case 0xcd:
x86emuOp_int_IMM(emu);
break;
case 0xce:
x86emuOp_into(emu);
break;
case 0xcf:
x86emuOp_iret(emu);
break;
case 0xd0:
x86emuOp_opcD0_byte_RM_1(emu);
break;
case 0xd1:
x86emuOp_opcD1_word_RM_1(emu);
break;
case 0xd2:
x86emuOp_opcD2_byte_RM_CL(emu);
break;
case 0xd3:
x86emuOp_opcD3_word_RM_CL(emu);
break;
case 0xd4:
x86emuOp_aam(emu);
break;
case 0xd5:
x86emuOp_aad(emu);
break;
/* 0xd6 Undocumented SETALC instruction */
case 0xd7:
x86emuOp_xlat(emu);
break;
case 0xd8:
x86emuOp_esc_coprocess_d8(emu);
break;
case 0xd9:
x86emuOp_esc_coprocess_d9(emu);
break;
case 0xda:
x86emuOp_esc_coprocess_da(emu);
break;
case 0xdb:
x86emuOp_esc_coprocess_db(emu);
break;
case 0xdc:
x86emuOp_esc_coprocess_dc(emu);
break;
case 0xdd:
x86emuOp_esc_coprocess_dd(emu);
break;
case 0xde:
x86emuOp_esc_coprocess_de(emu);
break;
case 0xdf:
x86emuOp_esc_coprocess_df(emu);
break;
case 0xe0:
x86emuOp_loopne(emu);
break;
case 0xe1:
x86emuOp_loope(emu);
break;
case 0xe2:
x86emuOp_loop(emu);
break;
case 0xe3:
x86emuOp_jcxz(emu);
break;
case 0xe4:
x86emuOp_in_byte_AL_IMM(emu);
break;
case 0xe5:
x86emuOp_in_word_AX_IMM(emu);
break;
case 0xe6:
x86emuOp_out_byte_IMM_AL(emu);
break;
case 0xe7:
x86emuOp_out_word_IMM_AX(emu);
break;
case 0xe8:
x86emuOp_call_near_IMM(emu);
break;
case 0xe9:
x86emuOp_jump_near_IMM(emu);
break;
case 0xea:
x86emuOp_jump_far_IMM(emu);
break;
case 0xeb:
x86emuOp_jump_byte_IMM(emu);
break;
case 0xec:
x86emuOp_in_byte_AL_DX(emu);
break;
case 0xed:
x86emuOp_in_word_AX_DX(emu);
break;
case 0xee:
x86emuOp_out_byte_DX_AL(emu);
break;
case 0xef:
x86emuOp_out_word_DX_AX(emu);
break;
case 0xf0:
x86emuOp_lock(emu);
break;
case 0xf2:
emu->x86.mode |= SYSMODE_PREFIX_REPNE;
break;
case 0xf3:
emu->x86.mode |= SYSMODE_PREFIX_REPE;
break;
case 0xf4:
X86EMU_halt_sys(emu);
break;
case 0xf5:
x86emuOp_cmc(emu);
break;
case 0xf6:
x86emuOp_opcF6_byte_RM(emu);
break;
case 0xf7:
x86emuOp_opcF7_word_RM(emu);
break;
case 0xf8:
CLEAR_FLAG(F_CF);
break;
case 0xf9:
SET_FLAG(F_CF);
break;
case 0xfa:
CLEAR_FLAG(F_IF);
break;
case 0xfb:
SET_FLAG(F_IF);
break;
case 0xfc:
CLEAR_FLAG(F_DF);
break;
case 0xfd:
SET_FLAG(F_DF);
break;
case 0xfe:
x86emuOp_opcFE_byte_RM(emu);
break;
case 0xff:
x86emuOp_opcFF_word_RM(emu);
break;
default:
X86EMU_halt_sys(emu);
break;
}
if (op1 != 0x26 && op1 != 0x2e && op1 != 0x36 && op1 != 0x3e &&
(op1 | 3) != 0x67)
emu->x86.mode &= ~SYSMODE_CLRMASK;
}
case 0x80:
common_jmp_long(emu, ACCESS_FLAG(F_OF));
break;
case 0x81:
common_jmp_long(emu, !ACCESS_FLAG(F_OF));
break;
case 0x82:
common_jmp_long(emu, ACCESS_FLAG(F_CF));
break;
case 0x83:
common_jmp_long(emu, !ACCESS_FLAG(F_CF));
break;
case 0x84:
common_jmp_long(emu, ACCESS_FLAG(F_ZF));
break;
case 0x85:
common_jmp_long(emu, !ACCESS_FLAG(F_ZF));
break;
case 0x86:
common_jmp_long(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
break;
case 0x87:
common_jmp_long(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
break;
case 0x88:
common_jmp_long(emu, ACCESS_FLAG(F_SF));
break;
case 0x89:
common_jmp_long(emu, !ACCESS_FLAG(F_SF));
break;
case 0x8a:
common_jmp_long(emu, ACCESS_FLAG(F_PF));
break;
case 0x8b:
common_jmp_long(emu, !ACCESS_FLAG(F_PF));
break;
case 0x8c:
common_jmp_long(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)));
break;
case 0x8d:
common_jmp_long(emu, !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))));
break;
case 0x8e:
common_jmp_long(emu,
(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || ACCESS_FLAG(F_ZF)));
break;
case 0x8f:
common_jmp_long(emu,
!(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || ACCESS_FLAG(F_ZF)));
break;
case 0x90:
common_set_byte(emu, ACCESS_FLAG(F_OF));
break;
case 0x91:
common_set_byte(emu, !ACCESS_FLAG(F_OF));
break;
case 0x92:
common_set_byte(emu, ACCESS_FLAG(F_CF));
break;
case 0x93:
common_set_byte(emu, !ACCESS_FLAG(F_CF));
break;
case 0x94:
common_set_byte(emu, ACCESS_FLAG(F_ZF));
break;
case 0x95:
common_set_byte(emu, !ACCESS_FLAG(F_ZF));
break;
case 0x96:
common_set_byte(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
break;
case 0x97:
common_set_byte(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
break;
case 0x98:
common_set_byte(emu, ACCESS_FLAG(F_SF));
break;
case 0x99:
common_set_byte(emu, !ACCESS_FLAG(F_SF));
break;
case 0x9a:
common_set_byte(emu, ACCESS_FLAG(F_PF));
break;
case 0x9b:
common_set_byte(emu, !ACCESS_FLAG(F_PF));
break;
case 0x9c:
common_set_byte(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)));
break;
case 0x9d:
common_set_byte(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)));
break;
case 0x9e:
common_set_byte(emu,
(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
ACCESS_FLAG(F_ZF)));
break;
case 0x9f:
common_set_byte(emu,
!(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
ACCESS_FLAG(F_ZF)));
break;
case 0xa0:
x86emuOp2_push_FS(emu);
break;
case 0xa1:
x86emuOp2_pop_FS(emu);
break;
case 0xa2:
x86emuOp2_cpuid(emu);
break;
case 0xa3:
x86emuOp2_bt_R(emu);
break;
case 0xa4:
x86emuOp2_shld_IMM(emu);
break;
case 0xa5:
x86emuOp2_shld_CL(emu);
break;
case 0xa8:
x86emuOp2_push_GS(emu);
break;
case 0xa9:
x86emuOp2_pop_GS(emu);
break;
case 0xab:
x86emuOp2_bts_R(emu);
break;
case 0xac:
x86emuOp2_shrd_IMM(emu);
break;
case 0xad:
x86emuOp2_shrd_CL(emu);
break;
case 0xaf:
x86emuOp2_imul_R_RM(emu);
break;
/* 0xb0 TODO: cmpxchg */
/* 0xb1 TODO: cmpxchg */
case 0xb2:
x86emuOp2_lss_R_IMM(emu);
break;
case 0xb3:
x86emuOp2_btr_R(emu);
break;
case 0xb4:
x86emuOp2_lfs_R_IMM(emu);
break;
case 0xb5:
x86emuOp2_lgs_R_IMM(emu);
break;
case 0xb6:
x86emuOp2_movzx_byte_R_RM(emu);
break;
case 0xb7:
x86emuOp2_movzx_word_R_RM(emu);
break;
case 0xba:
x86emuOp2_btX_I(emu);
break;
case 0xbb:
x86emuOp2_btc_R(emu);
break;
case 0xbc:
x86emuOp2_bsf(emu);
break;
case 0xbd:
x86emuOp2_bsr(emu);
break;
case 0xbe:
x86emuOp2_movsx_byte_R_RM(emu);
break;
case 0xbf:
x86emuOp2_movsx_word_R_RM(emu);
break;
/*
* Carry Chain Calculation
*
* This represents a somewhat expensive calculation which is
* apparently required to emulate the setting of the OF and AF flag.
* The latter is not so important, but the former is. The overflow
* flag is the XOR of the top two bits of the carry chain for an
* addition (similar for subtraction). Since we do not want to
* simulate the addition in a bitwise manner, we try to calculate the
* carry chain given the two operands and the result.
*
* So, given the following table, which represents the addition of two
* bits, we can derive a formula for the carry chain.
*
* a b cin r cout
* 0 0 0 0 0
* 0 0 1 1 0
* 0 1 0 1 0
* 0 1 1 0 1
* 1 0 0 1 0
* 1 0 1 0 1
* 1 1 0 0 1
* 1 1 1 1 1
*
* Construction of table for cout:
*
* ab
* r \ 00 01 11 10
* |------------------
* 0 | 0 1 1 1
* 1 | 0 0 1 0
*
* By inspection, one gets: cc = ab + r'(a + b)
*
* That represents alot of operations, but NO CHOICE....
*
* Borrow Chain Calculation.
*
* The following table represents the subtraction of two bits, from
* which we can derive a formula for the borrow chain.
*
* a b bin r bout
* 0 0 0 0 0
* 0 0 1 1 1
* 0 1 0 1 1
* 0 1 1 0 1
* 1 0 0 1 0
* 1 0 1 0 0
* 1 1 0 0 0
* 1 1 1 1 1
*
* Construction of table for cout:
*
* ab
* r \ 00 01 11 10
* |------------------
* 0 | 0 1 0 0
* 1 | 1 1 1 0
*
* By inspection, one gets: bc = a'b + r(a' + b)
*
****************************************************************************/
/*------------------------- Global Variables ------------------------------*/
/* calculate the carry chain SEE NOTE AT TOP. */
cc = (s & d) | ((~res) & (s | d));
CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the ADC instruction and side effects.
****************************************************************************/
static uint32_t
adc_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t lo; /* all operands in native machine order */
uint32_t hi;
uint32_t res;
uint32_t cc;
if (ACCESS_FLAG(F_CF)) {
lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
res = 1 + d + s;
} else {
lo = (d & 0xFFFF) + (s & 0xFFFF);
res = d + s;
}
hi = (lo >> 16) + (d >> 16) + (s >> 16);
/* calculate the carry chain SEE NOTE AT TOP. */
cc = (s & d) | ((~res) & (s | d));
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the AND instruction and side effects.
****************************************************************************/
static uint8_t
and_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint8_t res; /* all operands in native machine order */
res = d & s;
/* set the flags */
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the AND instruction and side effects.
****************************************************************************/
static uint16_t
and_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint16_t res; /* all operands in native machine order */
res = d & s;
/* set the flags */
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the AND instruction and side effects.
****************************************************************************/
static uint32_t
and_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
res = d & s;
/* set the flags */
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the CMP instruction and side effects.
****************************************************************************/
static uint8_t
cmp_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CLEAR_FLAG(F_CF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return d;
}
static void
cmp_byte_no_return(struct X86EMU *emu, uint8_t d, uint8_t s)
{
cmp_byte(emu, d, s);
}
/****************************************************************************
REMARKS:
Implements the CMP instruction and side effects.
****************************************************************************/
static uint16_t
cmp_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return d;
}
static void
cmp_word_no_return(struct X86EMU *emu, uint16_t d, uint16_t s)
{
cmp_word(emu, d, s);
}
/****************************************************************************
REMARKS:
Implements the CMP instruction and side effects.
****************************************************************************/
static uint32_t
cmp_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return d;
}
static void
cmp_long_no_return(struct X86EMU *emu, uint32_t d, uint32_t s)
{
cmp_long(emu, d, s);
}
/****************************************************************************
REMARKS:
Implements the DAA instruction and side effects.
****************************************************************************/
static uint8_t
daa_byte(struct X86EMU *emu, uint8_t d)
{
uint32_t res = d;
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
res += 6;
SET_FLAG(F_AF);
}
if (res > 0x9F || ACCESS_FLAG(F_CF)) {
res += 0x60;
SET_FLAG(F_CF);
}
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the DAS instruction and side effects.
****************************************************************************/
static uint8_t
das_byte(struct X86EMU *emu, uint8_t d)
{
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
d -= 6;
SET_FLAG(F_AF);
}
if (d > 0x9F || ACCESS_FLAG(F_CF)) {
d -= 0x60;
SET_FLAG(F_CF);
}
CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
CONDITIONAL_SET_FLAG(d == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
return d;
}
/****************************************************************************
REMARKS:
Implements the DEC instruction and side effects.
****************************************************************************/
static uint8_t
dec_byte(struct X86EMU *emu, uint8_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - 1;
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
/* based on sub_byte, uses s==1. */
bc = (res & (~d | 1)) | (~d & 1);
/* carry flag unchanged */
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the DEC instruction and side effects.
****************************************************************************/
static uint16_t
dec_word(struct X86EMU *emu, uint16_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - 1;
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
/* based on the sub_byte routine, with s==1 */
bc = (res & (~d | 1)) | (~d & 1);
/* carry flag unchanged */
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the DEC instruction and side effects.
****************************************************************************/
static uint32_t
dec_long(struct X86EMU *emu, uint32_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
/* calculate the borrow chain. See note at top */
bc = (res & (~d | 1)) | (~d & 1);
/* carry flag unchanged */
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the INC instruction and side effects.
****************************************************************************/
static uint8_t
inc_byte(struct X86EMU *emu, uint8_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t cc;
res = d + 1;
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the carry chain SEE NOTE AT TOP. */
cc = ((1 & d) | (~res)) & (1 | d);
CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the INC instruction and side effects.
****************************************************************************/
static uint16_t
inc_word(struct X86EMU *emu, uint16_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t cc;
res = d + 1;
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the carry chain SEE NOTE AT TOP. */
cc = (1 & d) | ((~res) & (1 | d));
CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the INC instruction and side effects.
****************************************************************************/
static uint32_t
inc_long(struct X86EMU *emu, uint32_t d)
{
uint32_t res; /* all operands in native machine order */
uint32_t cc;
res = d + 1;
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the carry chain SEE NOTE AT TOP. */
cc = (1 & d) | ((~res) & (1 | d));
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint8_t
or_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint8_t res; /* all operands in native machine order */
res = d | s;
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint16_t
or_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint16_t res; /* all operands in native machine order */
res = d | s;
/* set the carry flag to be bit 8 */
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint32_t
or_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
res = d | s;
/* set the carry flag to be bit 8 */
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint8_t
neg_byte(struct X86EMU *emu, uint8_t s)
{
uint8_t res;
uint8_t bc;
CONDITIONAL_SET_FLAG(s != 0, F_CF);
res = (uint8_t) - s;
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
/* calculate the borrow chain --- modified such that d=0.
* substituting d=0 into bc= res&(~d|s)|(~d&s); (the one used for
* sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
* res&0xfff... == res. Similarly ~d&s == s. So the simplified
* result is: */
bc = res | s;
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint16_t
neg_word(struct X86EMU *emu, uint16_t s)
{
uint16_t res;
uint16_t bc;
/* calculate the borrow chain --- modified such that d=0.
* substituting d=0 into bc= res&(~d|s)|(~d&s); (the one used for
* sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
* res&0xfff... == res. Similarly ~d&s == s. So the simplified
* result is: */
bc = res | s;
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the OR instruction and side effects.
****************************************************************************/
static uint32_t
neg_long(struct X86EMU *emu, uint32_t s)
{
uint32_t res;
uint32_t bc;
/* calculate the borrow chain --- modified such that d=0.
* substituting d=0 into bc= res&(~d|s)|(~d&s); (the one used for
* sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
* res&0xfff... == res. Similarly ~d&s == s. So the simplified
* result is: */
bc = res | s;
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the RCL instruction and side effects.
****************************************************************************/
static uint8_t
rcl_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int res, cnt, mask, cf;
/* s is the rotate distance. It varies from 0 - 8. */
/* have
*
* CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
*
* want to rotate through the carry by "s" bits. We could loop, but
* that's inefficient. So the width is 9, and we split into three
* parts:
*
* The new carry flag (was B_n) the stuff in B_n-1 .. B_0 the stuff in
* B_7 .. B_n+1
*
* The new rotate is done mod 9, and given this, for a rotation of n bits
* (mod 9) the new carry flag is then located n bits from the MSB.
* The low part is then shifted up cnt bits, and the high part is or'd
* in. Using CAPS for new values, and lowercase for the original
* values, this can be expressed as:
*
* IF n > 0 1) CF <- b_(8-n) 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
* 3) B_(n-1) <- cf 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */
res = d;
if ((cnt = s % 9) != 0) {
/* extract the new CARRY FLAG. */
/* CF <- b_(8-n) */
cf = (d >> (8 - cnt)) & 0x1;
/* get the low stuff which rotated into the range B_7 .. B_cnt */
/* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */
/* note that the right hand side done by the mask */
res = (d << cnt) & 0xff;
/* now the high stuff which rotated around into the positions
* B_cnt-2 .. B_0 */
/* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */
/* shift it downward, 7-(n-2) = 9-n positions. and mask off
* the result before or'ing in. */
mask = (1 << (cnt - 1)) - 1;
res |= (d >> (9 - cnt)) & mask;
/* if the carry flag was set, or it in. */
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
/* B_(n-1) <- cf */
res |= 1 << (cnt - 1);
}
/* set the new carry flag, based on the variable "cf" */
CONDITIONAL_SET_FLAG(cf, F_CF);
/* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
* the most significant bit. Blecck. */
/* parenthesized this expression since it appears to be
* causing OF to be misset */
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
F_OF);
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the RCL instruction and side effects.
****************************************************************************/
static uint16_t
rcl_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int res, cnt, mask, cf;
res = d;
if ((cnt = s % 33) != 0) {
cf = (d >> (32 - cnt)) & 0x1;
res = (d << cnt) & 0xffffffff;
mask = (1 << (cnt - 1)) - 1;
res |= (d >> (33 - cnt)) & mask;
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
res |= 1 << (cnt - 1);
}
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
F_OF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the RCR instruction and side effects.
****************************************************************************/
static uint8_t
rcr_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint32_t res, cnt;
uint32_t mask, cf, ocf = 0;
/* rotate right through carry */
/* s is the rotate distance. It varies from 0 - 8. d is the byte
* object rotated.
*
* have
*
* CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
*
* The new rotate is done mod 9, and given this, for a rotation of n bits
* (mod 9) the new carry flag is then located n bits from the LSB.
* The low part is then shifted up cnt bits, and the high part is or'd
* in. Using CAPS for new values, and lowercase for the original
* values, this can be expressed as:
*
* IF n > 0 1) CF <- b_(n-1) 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
* 3) B_(8-n) <- cf 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
res = d;
if ((cnt = s % 9) != 0) {
/* extract the new CARRY FLAG. */
/* CF <- b_(n-1) */
if (cnt == 1) {
cf = d & 0x1;
/* note hackery here. Access_flag(..) evaluates to
* either 0 if flag not set non-zero if flag is set.
* doing access_flag(..) != 0 casts that into either
* 0..1 in any representation of the flags register
* (i.e. packed bit array or unpacked.) */
ocf = ACCESS_FLAG(F_CF) != 0;
} else
cf = (d >> (cnt - 1)) & 0x1;
/* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
/* note that the right hand side done by the mask This is
* effectively done by shifting the object to the right. The
* result must be masked, in case the object came in and was
* treated as a negative number. Needed??? */
/* now the high stuff which rotated around into the positions
* B_cnt-2 .. B_0 */
/* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
/* shift it downward, 7-(n-2) = 9-n positions. and mask off
* the result before or'ing in. */
res |= (d << (9 - cnt));
/* if the carry flag was set, or it in. */
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
/* B_(8-n) <- cf */
res |= 1 << (8 - cnt);
}
/* set the new carry flag, based on the variable "cf" */
CONDITIONAL_SET_FLAG(cf, F_CF);
/* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
* the most significant bit. Blecck. */
/* parenthesized... */
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
F_OF);
}
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the RCR instruction and side effects.
****************************************************************************/
static uint16_t
rcr_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
uint32_t res, cnt;
uint32_t mask, cf, ocf = 0;
/* rotate right through carry */
res = d;
if ((cnt = s % 17) != 0) {
if (cnt == 1) {
cf = d & 0x1;
ocf = ACCESS_FLAG(F_CF) != 0;
} else
cf = (d >> (cnt - 1)) & 0x1;
mask = (1 << (16 - cnt)) - 1;
res = (d >> cnt) & mask;
res |= (d << (17 - cnt));
if (ACCESS_FLAG(F_CF)) {
res |= 1 << (16 - cnt);
}
CONDITIONAL_SET_FLAG(cf, F_CF);
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
F_OF);
}
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the RCR instruction and side effects.
****************************************************************************/
static uint32_t
rcr_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
uint32_t res, cnt;
uint32_t mask, cf, ocf = 0;
/* rotate right through carry */
res = d;
if ((cnt = s % 33) != 0) {
if (cnt == 1) {
cf = d & 0x1;
ocf = ACCESS_FLAG(F_CF) != 0;
} else
cf = (d >> (cnt - 1)) & 0x1;
mask = (1 << (32 - cnt)) - 1;
res = (d >> cnt) & mask;
if (cnt != 1)
res |= (d << (33 - cnt));
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
res |= 1 << (32 - cnt);
}
CONDITIONAL_SET_FLAG(cf, F_CF);
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
F_OF);
}
}
return res;
}
/****************************************************************************
REMARKS:
Implements the ROL instruction and side effects.
****************************************************************************/
static uint8_t
rol_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int res, cnt, mask;
/* rotate left */
/* s is the rotate distance. It varies from 0 - 8. d is the byte
* object rotated.
*
* have
*
* CF B_7 ... B_0
*
* The new rotate is done mod 8. Much simpler than the "rcl" or "rcr"
* operations.
*
* IF n > 0 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) 2) B_(n-1) ..
* B_(0) <- b_(7) .. b_(8-n) */
res = d;
if ((cnt = s % 8) != 0) {
/* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
res = (d << cnt);
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
/* OVERFLOW is set *IFF* s==1, then it is the xor of CF and
* the most significant bit. Blecck. */
CONDITIONAL_SET_FLAG(s == 1 &&
XOR2((res & 0x1) + ((res >> 6) & 0x2)),
F_OF);
} if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the ROL instruction and side effects.
****************************************************************************/
static uint16_t
rol_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int res, cnt, mask;
res = d;
if ((cnt = s % 16) != 0) {
res = (d << cnt);
mask = (1 << cnt) - 1;
res |= (d >> (16 - cnt)) & mask;
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
CONDITIONAL_SET_FLAG(s == 1 &&
XOR2((res & 0x1) + ((res >> 14) & 0x2)),
F_OF);
} if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the ROL instruction and side effects.
****************************************************************************/
static uint32_t
rol_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
uint32_t res, cnt, mask;
res = d;
if ((cnt = s % 32) != 0) {
res = (d << cnt);
mask = (1 << cnt) - 1;
res |= (d >> (32 - cnt)) & mask;
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
CONDITIONAL_SET_FLAG(s == 1 &&
XOR2((res & 0x1) + ((res >> 30) & 0x2)),
F_OF);
} if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the ROR instruction and side effects.
****************************************************************************/
static uint8_t
ror_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int res, cnt, mask;
/* rotate right */
/* s is the rotate distance. It varies from 0 - 8. d is the byte
* object rotated.
*
* have
*
* B_7 ... B_0
*
* The rotate is done mod 8.
*
* IF n > 0 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 2) B_(7) ..
* B_(8-n) <- b_(n-1) .. b_(0) */
res = d;
if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */
/* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */
res = (d << (8 - cnt));
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
/* OVERFLOW is set *IFF* s==1, then it is the xor of the two
* most significant bits. Blecck. */
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
} else if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the ROR instruction and side effects.
****************************************************************************/
static uint16_t
ror_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int res, cnt, mask;
res = d;
if ((cnt = s % 16) != 0) {
res = (d << (16 - cnt));
mask = (1 << (16 - cnt)) - 1;
res |= (d >> (cnt)) & mask;
CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
} else if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the ROR instruction and side effects.
****************************************************************************/
static uint32_t
ror_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
uint32_t res, cnt, mask;
res = d;
if ((cnt = s % 32) != 0) {
res = (d << (32 - cnt));
mask = (1 << (32 - cnt)) - 1;
res |= (d >> (cnt)) & mask;
CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
} else if (s != 0) {
/* set the new carry flag, Note that it is the low order bit
* of the result!!! */
CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SHL instruction and side effects.
****************************************************************************/
static uint8_t
shl_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 8) {
cnt = s % 8;
/* last bit shifted out goes into carry flag */
if (cnt > 0) {
res = d << cnt;
cf = d & (1 << (8 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = (uint8_t) d;
}
if (cnt == 1) {
/* Needs simplification. */
CONDITIONAL_SET_FLAG(
(((res & 0x80) == 0x80) ^
(ACCESS_FLAG(F_CF) != 0)),
/* was (emu->x86.R_FLG&F_CF)==F_CF)), */
F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHL instruction and side effects.
****************************************************************************/
static uint16_t
shl_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 16) {
cnt = s % 16;
if (cnt > 0) {
res = d << cnt;
cf = d & (1 << (16 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = (uint16_t) d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(
(((res & 0x8000) == 0x8000) ^
(ACCESS_FLAG(F_CF) != 0)),
F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHL instruction and side effects.
****************************************************************************/
static uint32_t
shl_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 32) {
cnt = s % 32;
if (cnt > 0) {
res = d << cnt;
cf = d & (1 << (32 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
(ACCESS_FLAG(F_CF) != 0)), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SHR instruction and side effects.
****************************************************************************/
static uint8_t
shr_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 8) {
cnt = s % 8;
if (cnt > 0) {
cf = d & (1 << (cnt - 1));
res = d >> cnt;
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = (uint8_t) d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHR instruction and side effects.
****************************************************************************/
static uint16_t
shr_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 16) {
cnt = s % 16;
if (cnt > 0) {
cf = d & (1 << (cnt - 1));
res = d >> cnt;
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHR instruction and side effects.
****************************************************************************/
static uint32_t
shr_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 32) {
cnt = s % 32;
if (cnt > 0) {
cf = d & (1 << (cnt - 1));
res = d >> cnt;
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SAR instruction and side effects.
****************************************************************************/
static uint8_t
sar_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
unsigned int cnt, res, cf, mask, sf;
res = d;
sf = d & 0x80;
cnt = s % 8;
if (cnt > 0 && cnt < 8) {
mask = (1 << (8 - cnt)) - 1;
cf = d & (1 << (cnt - 1));
res = (d >> cnt) & mask;
CONDITIONAL_SET_FLAG(cf, F_CF);
if (sf) {
res |= ~mask;
}
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
} else if (cnt >= 8) {
if (sf) {
res = 0xff;
SET_FLAG(F_CF);
CLEAR_FLAG(F_ZF);
SET_FLAG(F_SF);
SET_FLAG(F_PF);
} else {
res = 0;
CLEAR_FLAG(F_CF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
}
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the SAR instruction and side effects.
****************************************************************************/
static uint16_t
sar_word(struct X86EMU *emu, uint16_t d, uint8_t s)
{
unsigned int cnt, res, cf, mask, sf;
sf = d & 0x8000;
cnt = s % 16;
res = d;
if (cnt > 0 && cnt < 16) {
mask = (1 << (16 - cnt)) - 1;
cf = d & (1 << (cnt - 1));
res = (d >> cnt) & mask;
CONDITIONAL_SET_FLAG(cf, F_CF);
if (sf) {
res |= ~mask;
}
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else if (cnt >= 16) {
if (sf) {
res = 0xffff;
SET_FLAG(F_CF);
CLEAR_FLAG(F_ZF);
SET_FLAG(F_SF);
SET_FLAG(F_PF);
} else {
res = 0;
CLEAR_FLAG(F_CF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SAR instruction and side effects.
****************************************************************************/
static uint32_t
sar_long(struct X86EMU *emu, uint32_t d, uint8_t s)
{
uint32_t cnt, res, cf, mask, sf;
sf = d & 0x80000000;
cnt = s % 32;
res = d;
if (cnt > 0 && cnt < 32) {
mask = (1 << (32 - cnt)) - 1;
cf = d & (1 << (cnt - 1));
res = (d >> cnt) & mask;
CONDITIONAL_SET_FLAG(cf, F_CF);
if (sf) {
res |= ~mask;
}
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else if (cnt >= 32) {
if (sf) {
res = 0xffffffff;
SET_FLAG(F_CF);
CLEAR_FLAG(F_ZF);
SET_FLAG(F_SF);
SET_FLAG(F_PF);
} else {
res = 0;
CLEAR_FLAG(F_CF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SHLD instruction and side effects.
****************************************************************************/
static uint16_t
shld_word(struct X86EMU *emu, uint16_t d, uint16_t fill, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 16) {
cnt = s % 16;
if (cnt > 0) {
res = (d << cnt) | (fill >> (16 - cnt));
cf = d & (1 << (16 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
(ACCESS_FLAG(F_CF) != 0)), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHLD instruction and side effects.
****************************************************************************/
static uint32_t
shld_long(struct X86EMU *emu, uint32_t d, uint32_t fill, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 32) {
cnt = s % 32;
if (cnt > 0) {
res = (d << cnt) | (fill >> (32 - cnt));
cf = d & (1 << (32 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
(ACCESS_FLAG(F_CF) != 0)), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
CLEAR_FLAG(F_OF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_PF);
SET_FLAG(F_ZF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SHRD instruction and side effects.
****************************************************************************/
static uint16_t
shrd_word(struct X86EMU *emu, uint16_t d, uint16_t fill, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 16) {
cnt = s % 16;
if (cnt > 0) {
cf = d & (1 << (cnt - 1));
res = (d >> cnt) | (fill << (16 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SHRD instruction and side effects.
****************************************************************************/
static uint32_t
shrd_long(struct X86EMU *emu, uint32_t d, uint32_t fill, uint8_t s)
{
unsigned int cnt, res, cf;
if (s < 32) {
cnt = s % 32;
if (cnt > 0) {
cf = d & (1 << (cnt - 1));
res = (d >> cnt) | (fill << (32 - cnt));
CONDITIONAL_SET_FLAG(cf, F_CF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
} else {
res = d;
}
if (cnt == 1) {
CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
} else {
CLEAR_FLAG(F_OF);
}
} else {
res = 0;
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
SET_FLAG(F_ZF);
CLEAR_FLAG(F_SF);
CLEAR_FLAG(F_PF);
}
return res;
}
/****************************************************************************
REMARKS:
Implements the SBB instruction and side effects.
****************************************************************************/
static uint8_t
sbb_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
if (ACCESS_FLAG(F_CF))
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the SBB instruction and side effects.
****************************************************************************/
static uint16_t
sbb_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
if (ACCESS_FLAG(F_CF))
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SBB instruction and side effects.
****************************************************************************/
static uint32_t
sbb_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
if (ACCESS_FLAG(F_CF))
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the SUB instruction and side effects.
****************************************************************************/
static uint8_t
sub_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint8_t) res;
}
/****************************************************************************
REMARKS:
Implements the SUB instruction and side effects.
****************************************************************************/
static uint16_t
sub_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return (uint16_t) res;
}
/****************************************************************************
REMARKS:
Implements the SUB instruction and side effects.
****************************************************************************/
static uint32_t
sub_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
uint32_t bc;
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the TEST instruction and side effects.
****************************************************************************/
static void
test_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint32_t res; /* all operands in native machine order */
res = d & s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* AF == dont care */
CLEAR_FLAG(F_CF);
}
/****************************************************************************
REMARKS:
Implements the TEST instruction and side effects.
****************************************************************************/
static void
test_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint32_t res; /* all operands in native machine order */
res = d & s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* AF == dont care */
CLEAR_FLAG(F_CF);
}
/****************************************************************************
REMARKS:
Implements the TEST instruction and side effects.
****************************************************************************/
static void
test_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
res = d & s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* AF == dont care */
CLEAR_FLAG(F_CF);
}
/****************************************************************************
REMARKS:
Implements the XOR instruction and side effects.
****************************************************************************/
static uint8_t
xor_byte(struct X86EMU *emu, uint8_t d, uint8_t s)
{
uint8_t res; /* all operands in native machine order */
res = d ^ s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the XOR instruction and side effects.
****************************************************************************/
static uint16_t
xor_word(struct X86EMU *emu, uint16_t d, uint16_t s)
{
uint16_t res; /* all operands in native machine order */
res = d ^ s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the XOR instruction and side effects.
****************************************************************************/
static uint32_t
xor_long(struct X86EMU *emu, uint32_t d, uint32_t s)
{
uint32_t res; /* all operands in native machine order */
res = d ^ s;
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
return res;
}
/****************************************************************************
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static void
imul_byte(struct X86EMU *emu, uint8_t s)
{
int16_t res = (int16_t) ((int8_t) emu->x86.R_AL * (int8_t) s);
dvd = (((int64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
if (s == 0) {
x86emu_intr_raise(emu, 8);
return;
}
div = dvd / (int32_t) s;
mod = dvd % (int32_t) s;
if (div > 0x7fffffff || div < -0x7fffffff) {
x86emu_intr_raise(emu, 8);
return;
}
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_ZF);
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
emu->x86.R_EAX = (uint32_t) div;
emu->x86.R_EDX = (uint32_t) mod;
}
/****************************************************************************
REMARKS:
Implements the DIV instruction and side effects.
****************************************************************************/
static void
div_byte(struct X86EMU *emu, uint8_t s)
{
uint32_t dvd, div, mod;
dvd = emu->x86.R_AX;
if (s == 0) {
x86emu_intr_raise(emu, 8);
return;
}
div = dvd / (uint8_t) s;
mod = dvd % (uint8_t) s;
if (div > 0xff) {
x86emu_intr_raise(emu, 8);
return;
}
emu->x86.R_AL = (uint8_t) div;
emu->x86.R_AH = (uint8_t) mod;
}
/****************************************************************************
REMARKS:
Implements the DIV instruction and side effects.
****************************************************************************/
static void
div_word(struct X86EMU *emu, uint16_t s)
{
uint32_t dvd, div, mod;
dvd = (((uint32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
if (s == 0) {
x86emu_intr_raise(emu, 8);
return;
}
div = dvd / (uint16_t) s;
mod = dvd % (uint16_t) s;
if (div > 0xffff) {
x86emu_intr_raise(emu, 8);
return;
}
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_SF);
CONDITIONAL_SET_FLAG(div == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
emu->x86.R_AX = (uint16_t) div;
emu->x86.R_DX = (uint16_t) mod;
}
/****************************************************************************
REMARKS:
Implements the DIV instruction and side effects.
****************************************************************************/
static void
div_long(struct X86EMU *emu, uint32_t s)
{
uint64_t dvd, div, mod;
dvd = (((uint64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
if (s == 0) {
x86emu_intr_raise(emu, 8);
return;
}
div = dvd / (uint32_t) s;
mod = dvd % (uint32_t) s;
if (div > 0xffffffff) {
x86emu_intr_raise(emu, 8);
return;
}
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
CLEAR_FLAG(F_SF);
SET_FLAG(F_ZF);
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
emu->x86.R_EAX = (uint32_t) div;
emu->x86.R_EDX = (uint32_t) mod;
}
/****************************************************************************
REMARKS:
Implements the IN string instruction and side effects.
****************************************************************************/
static void
ins(struct X86EMU *emu, int size)
{
int inc = size;
if (ACCESS_FLAG(F_DF)) {
inc = -size;
}
if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* dont care whether REPE or REPNE */
/* in until CX is ZERO. */
uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
emu->x86.R_ECX : emu->x86.R_CX);
switch (size) {
case 1:
while (count--) {
store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inb) (emu, emu->x86.R_DX));
emu->x86.R_DI += inc;
}
break;
case 2:
while (count--) {
store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inw) (emu, emu->x86.R_DX));
emu->x86.R_DI += inc;
}
break;
case 4:
while (count--) {
store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inl) (emu, emu->x86.R_DX));
emu->x86.R_DI += inc;
break;
}
}
emu->x86.R_CX = 0;
if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
emu->x86.R_ECX = 0;
}
emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
} else {
switch (size) {
case 1:
store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inb) (emu, emu->x86.R_DX));
break;
case 2:
store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inw) (emu, emu->x86.R_DX));
break;
case 4:
store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
(*emu->emu_inl) (emu, emu->x86.R_DX));
break;
}
emu->x86.R_DI += inc;
}
}
/****************************************************************************
REMARKS:
Implements the OUT string instruction and side effects.
****************************************************************************/
static void
outs(struct X86EMU *emu, int size)
{
int inc = size;
if (ACCESS_FLAG(F_DF)) {
inc = -size;
}
if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* dont care whether REPE or REPNE */
/* out until CX is ZERO. */
uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
emu->x86.R_ECX : emu->x86.R_CX);
switch (size) {
case 1:
while (count--) {
(*emu->emu_outb) (emu, emu->x86.R_DX,
fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI));
emu->x86.R_SI += inc;
}
break;
case 2:
while (count--) {
(*emu->emu_outw) (emu, emu->x86.R_DX,
fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI));
emu->x86.R_SI += inc;
}
break;
case 4:
while (count--) {
(*emu->emu_outl) (emu, emu->x86.R_DX,
fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI));
emu->x86.R_SI += inc;
break;
}
}
emu->x86.R_CX = 0;
if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
emu->x86.R_ECX = 0;
}
emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
} else {
switch (size) {
case 1:
(*emu->emu_outb) (emu, emu->x86.R_DX,
fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI));
break;
case 2:
(*emu->emu_outw) (emu, emu->x86.R_DX,
fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI));
break;
case 4:
(*emu->emu_outl) (emu, emu->x86.R_DX,
fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI));
break;
}
emu->x86.R_SI += inc;
}
}
/****************************************************************************
REMARKS:
Pushes a word onto the stack.
NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
push_word(struct X86EMU *emu, uint16_t w)
{
emu->x86.R_SP -= 2;
store_word(emu, emu->x86.R_SS, emu->x86.R_SP, w);
}
/****************************************************************************
REMARKS:
Pushes a long onto the stack.
NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
****************************************************************************/
static void
push_long(struct X86EMU *emu, uint32_t w)
{
emu->x86.R_SP -= 4;
store_long(emu, emu->x86.R_SS, emu->x86.R_SP, w);
}
/****************************************************************************
REMARKS:
Pops a word from the stack.
NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint16_t
pop_word(struct X86EMU *emu)
{
uint16_t res;
res = fetch_word(emu, emu->x86.R_SS, emu->x86.R_SP);
emu->x86.R_SP += 2;
return res;
}
/****************************************************************************
REMARKS:
Pops a long from the stack.
NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
****************************************************************************/
static uint32_t
pop_long(struct X86EMU *emu)
{
uint32_t res;