blob: eeaa2035448754520e364104c9bf0d935c919b6a [file] [log] [blame]
/****************************************************************************
*
* Realmode X86 Emulator Library
*
* Copyright (C) 1991-2004 SciTech Software, Inc.
* Copyright (C) David Mosberger-Tang
* Copyright (C) 1999 Egbert Eich
*
* ========================================================================
*
* 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.
*
* ========================================================================
*
* Language: ANSI C
* Environment: Any
* Developer: Kendall Bennett
*
* Description: This file includes subroutines to implement the decoding
* and emulation of all the x86 processor instructions.
*
* There are approximately 250 subroutines in here, which correspond
* to the 256 byte-"opcodes" found on the 8086. The table which
* dispatches this is found in the files optab.[ch].
*
* Each opcode proc has a comment preceding it which gives it's table
* address. Several opcodes are missing (undefined) in the table.
*
* Each proc includes information for decoding (DECODE_PRINTF and
* DECODE_PRINTF2), debugging (TRACE_REGS, SINGLE_STEP), and misc
* functions (START_OF_INSTR, END_OF_INSTR).
*
* Many of the procedures are *VERY* similar in coding. This has
* allowed for a very large amount of code to be generated in a fairly
* short amount of time (i.e. cut, paste, and modify). The result is
* that much of the code below could have been folded into subroutines
* for a large reduction in size of this file. The downside would be
* that there would be a penalty in execution speed. The file could
* also have been *MUCH* larger by inlining certain functions which
* were called. This could have resulted even faster execution. The
* prime directive I used to decide whether to inline the code or to
* modularize it, was basically: 1) no unnecessary subroutine calls,
* 2) no routines more than about 200 lines in size, and 3) modularize
* any code that I might not get right the first time. The fetch_*
* subroutines fall into the latter category. The decode_* fall
* into the second category. The coding of the "switch(mod){ .... }"
* in many of the subroutines below falls into the first category.
* Especially, the coding of {add,and,or,sub,...}_{byte,word}
* subroutines are an especially glaring case of the third guideline.
* Since so much of the code is cloned from other modules (compare
* opcode #00 to opcode #01), making the basic operations subroutine
* calls is especially important; otherwise mistakes in coding an
* "add" would represent a nightmare in maintenance.
*
****************************************************************************/
#include "x86emui.h"
/*----------------------------- Implementation ----------------------------*/
/* constant arrays to do several instructions in just one function */
#ifdef DEBUG
static const char *x86emu_GenOpName[8] = {
"ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"};
#endif
/* used by several opcodes */
static u8 (*genop_byte_operation[])(u8 d, u8 s) =
{
add_byte, /* 00 */
or_byte, /* 01 */
adc_byte, /* 02 */
sbb_byte, /* 03 */
and_byte, /* 04 */
sub_byte, /* 05 */
xor_byte, /* 06 */
cmp_byte, /* 07 */
};
static u16 (*genop_word_operation[])(u16 d, u16 s) =
{
add_word, /*00 */
or_word, /*01 */
adc_word, /*02 */
sbb_word, /*03 */
and_word, /*04 */
sub_word, /*05 */
xor_word, /*06 */
cmp_word, /*07 */
};
static u32 (*genop_long_operation[])(u32 d, u32 s) =
{
add_long, /*00 */
or_long, /*01 */
adc_long, /*02 */
sbb_long, /*03 */
and_long, /*04 */
sub_long, /*05 */
xor_long, /*06 */
cmp_long, /*07 */
};
/* used by opcodes 80, c0, d0, and d2. */
static u8(*opcD0_byte_operation[])(u8 d, u8 s) =
{
rol_byte,
ror_byte,
rcl_byte,
rcr_byte,
shl_byte,
shr_byte,
shl_byte, /* sal_byte === shl_byte by definition */
sar_byte,
};
/* used by opcodes c1, d1, and d3. */
static u16(*opcD1_word_operation[])(u16 s, u8 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 u32 (*opcD1_long_operation[])(u32 s, u8 d) =
{
rol_long,
ror_long,
rcl_long,
rcr_long,
shl_long,
shr_long,
shl_long, /* sal_byte === shl_byte by definition */
sar_long,
};
#ifdef DEBUG
static const char *opF6_names[8] =
{ "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" };
#endif
/****************************************************************************
PARAMETERS:
op1 - Instruction op code
REMARKS:
Handles illegal opcodes.
****************************************************************************/
static void x86emuOp_illegal_op(
u8 op1)
{
START_OF_INSTR();
if (M.x86.R_SP != 0) {
DECODE_PRINTF("ILLEGAL X86 OPCODE\n");
TRACE_REGS();
DB( printf("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n",
M.x86.R_CS, M.x86.R_IP-1,op1));
HALT_SYS();
}
else {
/* If we get here, it means the stack pointer is back to zero
* so we are just returning from an emulator service call
* so therte is no need to display an error message. We trap
* the emulator with an 0xF1 opcode to finish the service
* call.
*/
X86EMU_halt_sys();
}
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
****************************************************************************/
static void x86emuOp_genop_byte_RM_R(u8 op1)
{
int mod, rl, rh;
uint destoffset;
u8 *destreg, *srcreg;
u8 destval;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod<3)
{ destoffset = decode_rmXX_address(mod,rl);
DECODE_PRINTF(",");
destval = fetch_data_byte(destoffset);
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = genop_byte_operation[op1](destval, *srcreg);
if (op1 != 7)
store_data_byte(destoffset, destval);
}
else
{ /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_byte_operation[op1](*destreg, *srcreg);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39
****************************************************************************/
static void x86emuOp_genop_word_RM_R(u8 op1)
{
int mod, rl, rh;
uint destoffset;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod<3) {
destoffset = decode_rmXX_address(mod,rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 destval;
u32 *srcreg;
DECODE_PRINTF(",");
destval = fetch_data_long(destoffset);
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = genop_long_operation[op1](destval, *srcreg);
if (op1 != 7)
store_data_long(destoffset, destval);
} else {
u16 destval;
u16 *srcreg;
DECODE_PRINTF(",");
destval = fetch_data_word(destoffset);
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = genop_word_operation[op1](destval, *srcreg);
if (op1 != 7)
store_data_word(destoffset, destval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg, *srcreg;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_long_operation[op1](*destreg, *srcreg);
} else {
u16 *destreg, *srcreg;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_word_operation[op1](*destreg, *srcreg);
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a
****************************************************************************/
static void x86emuOp_genop_byte_R_RM(u8 op1)
{
int mod, rl, rh;
u8 *destreg, *srcreg;
uint srcoffset;
u8 srcval;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF(",");
srcoffset = decode_rmXX_address(mod,rl);
srcval = fetch_data_byte(srcoffset);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rl);
srcval = *srcreg;
}
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_byte_operation[op1](*destreg, srcval);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b
****************************************************************************/
static void x86emuOp_genop_word_R_RM(u8 op1)
{
int mod, rl, rh;
uint srcoffset;
u32 *destreg32, srcval;
u16 *destreg;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
srcoffset = decode_rmXX_address(mod,rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
destreg32 = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_long(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg32 = genop_long_operation[op1](*destreg32, srcval);
} else {
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_word(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_word_operation[op1](*destreg, srcval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *srcreg;
destreg32 = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg32 = genop_long_operation[op1](*destreg32, *srcreg);
} else {
u16 *srcreg;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = genop_word_operation[op1](*destreg, *srcreg);
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c
****************************************************************************/
static void x86emuOp_genop_byte_AL_IMM(u8 op1)
{
u8 srcval;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\tAL,");
srcval = fetch_byte_imm();
DECODE_PRINTF2("%x\n", srcval);
TRACE_AND_STEP();
M.x86.R_AL = genop_byte_operation[op1](M.x86.R_AL, srcval);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcodes 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d
****************************************************************************/
static void x86emuOp_genop_word_AX_IMM(u8 op1)
{
u32 srcval;
op1 = (op1 >> 3) & 0x7;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\tEAX,");
srcval = fetch_long_imm();
} else {
DECODE_PRINTF(x86emu_GenOpName[op1]);
DECODE_PRINTF("\tAX,");
srcval = fetch_word_imm();
}
DECODE_PRINTF2("%x\n", srcval);
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
M.x86.R_EAX = genop_long_operation[op1](M.x86.R_EAX, srcval);
} else {
M.x86.R_AX = genop_word_operation[op1](M.x86.R_AX, (u16)srcval);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x06
****************************************************************************/
static void x86emuOp_push_ES(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("PUSH\tES\n");
TRACE_AND_STEP();
push_word(M.x86.R_ES);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x07
****************************************************************************/
static void x86emuOp_pop_ES(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("POP\tES\n");
TRACE_AND_STEP();
M.x86.R_ES = pop_word();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x0e
****************************************************************************/
static void x86emuOp_push_CS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("PUSH\tCS\n");
TRACE_AND_STEP();
push_word(M.x86.R_CS);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x0f. Escape for two-byte opcode (286 or better)
****************************************************************************/
static void x86emuOp_two_byte(u8 X86EMU_UNUSED(op1))
{
u8 op2 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
INC_DECODED_INST_LEN(1);
(*x86emu_optab2[op2])(op2);
}
/****************************************************************************
REMARKS:
Handles opcode 0x16
****************************************************************************/
static void x86emuOp_push_SS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("PUSH\tSS\n");
TRACE_AND_STEP();
push_word(M.x86.R_SS);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x17
****************************************************************************/
static void x86emuOp_pop_SS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("POP\tSS\n");
TRACE_AND_STEP();
M.x86.R_SS = pop_word();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x1e
****************************************************************************/
static void x86emuOp_push_DS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("PUSH\tDS\n");
TRACE_AND_STEP();
push_word(M.x86.R_DS);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x1f
****************************************************************************/
static void x86emuOp_pop_DS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("POP\tDS\n");
TRACE_AND_STEP();
M.x86.R_DS = pop_word();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x26
****************************************************************************/
static void x86emuOp_segovr_ES(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("ES:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_ES;
/*
* note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
* opcode subroutines we do not want to do this.
*/
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x27
****************************************************************************/
static void x86emuOp_daa(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("DAA\n");
TRACE_AND_STEP();
M.x86.R_AL = daa_byte(M.x86.R_AL);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x2e
****************************************************************************/
static void x86emuOp_segovr_CS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("CS:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_CS;
/* note no DECODE_CLEAR_SEGOVR here. */
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x2f
****************************************************************************/
static void x86emuOp_das(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("DAS\n");
TRACE_AND_STEP();
M.x86.R_AL = das_byte(M.x86.R_AL);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x36
****************************************************************************/
static void x86emuOp_segovr_SS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("SS:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_SS;
/* no DECODE_CLEAR_SEGOVR ! */
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x37
****************************************************************************/
static void x86emuOp_aaa(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("AAA\n");
TRACE_AND_STEP();
M.x86.R_AX = aaa_word(M.x86.R_AX);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x3e
****************************************************************************/
static void x86emuOp_segovr_DS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("DS:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_DS;
/* NO DECODE_CLEAR_SEGOVR! */
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x3f
****************************************************************************/
static void x86emuOp_aas(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("AAS\n");
TRACE_AND_STEP();
M.x86.R_AX = aas_word(M.x86.R_AX);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x40 - 0x47
****************************************************************************/
static void x86emuOp_inc_register(u8 op1)
{
START_OF_INSTR();
op1 &= 0x7;
DECODE_PRINTF("INC\t");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *reg;
reg = DECODE_RM_LONG_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = inc_long(*reg);
} else {
u16 *reg;
reg = DECODE_RM_WORD_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = inc_word(*reg);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x48 - 0x4F
****************************************************************************/
static void x86emuOp_dec_register(u8 op1)
{
START_OF_INSTR();
op1 &= 0x7;
DECODE_PRINTF("DEC\t");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *reg;
reg = DECODE_RM_LONG_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = dec_long(*reg);
} else {
u16 *reg;
reg = DECODE_RM_WORD_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = dec_word(*reg);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x50 - 0x57
****************************************************************************/
static void x86emuOp_push_register(u8 op1)
{
START_OF_INSTR();
op1 &= 0x7;
DECODE_PRINTF("PUSH\t");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *reg;
reg = DECODE_RM_LONG_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
push_long(*reg);
} else {
u16 *reg;
reg = DECODE_RM_WORD_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
push_word(*reg);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x58 - 0x5F
****************************************************************************/
static void x86emuOp_pop_register(u8 op1)
{
START_OF_INSTR();
op1 &= 0x7;
DECODE_PRINTF("POP\t");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *reg;
reg = DECODE_RM_LONG_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = pop_long();
} else {
u16 *reg;
reg = DECODE_RM_WORD_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*reg = pop_word();
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x60
****************************************************************************/
static void x86emuOp_push_all(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("PUSHAD\n");
} else {
DECODE_PRINTF("PUSHA\n");
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 old_sp = M.x86.R_ESP;
push_long(M.x86.R_EAX);
push_long(M.x86.R_ECX);
push_long(M.x86.R_EDX);
push_long(M.x86.R_EBX);
push_long(old_sp);
push_long(M.x86.R_EBP);
push_long(M.x86.R_ESI);
push_long(M.x86.R_EDI);
} else {
u16 old_sp = M.x86.R_SP;
push_word(M.x86.R_AX);
push_word(M.x86.R_CX);
push_word(M.x86.R_DX);
push_word(M.x86.R_BX);
push_word(old_sp);
push_word(M.x86.R_BP);
push_word(M.x86.R_SI);
push_word(M.x86.R_DI);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x61
****************************************************************************/
static void x86emuOp_pop_all(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("POPAD\n");
} else {
DECODE_PRINTF("POPA\n");
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
M.x86.R_EDI = pop_long();
M.x86.R_ESI = pop_long();
M.x86.R_EBP = pop_long();
M.x86.R_ESP += 4; /* skip ESP */
M.x86.R_EBX = pop_long();
M.x86.R_EDX = pop_long();
M.x86.R_ECX = pop_long();
M.x86.R_EAX = pop_long();
} else {
M.x86.R_DI = pop_word();
M.x86.R_SI = pop_word();
M.x86.R_BP = pop_word();
M.x86.R_SP += 2; /* skip SP */
M.x86.R_BX = pop_word();
M.x86.R_DX = pop_word();
M.x86.R_CX = pop_word();
M.x86.R_AX = pop_word();
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */
/*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */
/****************************************************************************
REMARKS:
Handles opcode 0x64
****************************************************************************/
static void x86emuOp_segovr_FS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("FS:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_FS;
/*
* note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
* opcode subroutines we do not want to do this.
*/
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x65
****************************************************************************/
static void x86emuOp_segovr_GS(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("GS:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_SEGOVR_GS;
/*
* note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
* opcode subroutines we do not want to do this.
*/
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x66 - prefix for 32-bit register
****************************************************************************/
static void x86emuOp_prefix_data(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("DATA:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_PREFIX_DATA;
/* note no DECODE_CLEAR_SEGOVR here. */
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x67 - prefix for 32-bit address
****************************************************************************/
static void x86emuOp_prefix_addr(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("ADDR:\n");
TRACE_AND_STEP();
M.x86.mode |= SYSMODE_PREFIX_ADDR;
/* note no DECODE_CLEAR_SEGOVR here. */
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x68
****************************************************************************/
static void x86emuOp_push_word_IMM(u8 X86EMU_UNUSED(op1))
{
u32 imm;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
imm = fetch_long_imm();
} else {
imm = fetch_word_imm();
}
DECODE_PRINTF2("PUSH\t%x\n", imm);
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
push_long(imm);
} else {
push_word((u16)imm);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x69
****************************************************************************/
static void x86emuOp_imul_word_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint srcoffset;
START_OF_INSTR();
DECODE_PRINTF("IMUL\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
srcoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg;
u32 srcval;
u32 res_lo,res_hi;
s32 imm;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_long(srcoffset);
imm = fetch_long_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u32)res_lo;
} else {
u16 *destreg;
u16 srcval;
u32 res;
s16 imm;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_word(srcoffset);
imm = fetch_word_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
res = (s16)srcval * (s16)imm;
if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u16)res;
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg,*srcreg;
u32 res_lo,res_hi;
s32 imm;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rl);
imm = fetch_long_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u32)res_lo;
} else {
u16 *destreg,*srcreg;
u32 res;
s16 imm;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rl);
imm = fetch_word_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
res = (s16)*srcreg * (s16)imm;
if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u16)res;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6a
****************************************************************************/
static void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1))
{
s16 imm;
START_OF_INSTR();
imm = (s8)fetch_byte_imm();
DECODE_PRINTF2("PUSH\t%d\n", imm);
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
push_long(imm);
} else {
push_word(imm);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6b
****************************************************************************/
static void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint srcoffset;
s8 imm;
START_OF_INSTR();
DECODE_PRINTF("IMUL\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
srcoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg;
u32 srcval;
u32 res_lo,res_hi;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_long(srcoffset);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u32)res_lo;
} else {
u16 *destreg;
u16 srcval;
u32 res;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcval = fetch_data_word(srcoffset);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
res = (s16)srcval * (s16)imm;
if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u16)res;
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg,*srcreg;
u32 res_lo,res_hi;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rl);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u32)res_lo;
} else {
u16 *destreg,*srcreg;
u32 res;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rl);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%d\n", (s32)imm);
TRACE_AND_STEP();
res = (s16)*srcreg * (s16)imm;
if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_OF);
} else {
SET_FLAG(F_CF);
SET_FLAG(F_OF);
}
*destreg = (u16)res;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6c
****************************************************************************/
static void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("INSB\n");
ins(1);
TRACE_AND_STEP();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6d
****************************************************************************/
static void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("INSD\n");
ins(4);
} else {
DECODE_PRINTF("INSW\n");
ins(2);
}
TRACE_AND_STEP();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6e
****************************************************************************/
static void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("OUTSB\n");
outs(1);
TRACE_AND_STEP();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x6f
****************************************************************************/
static void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("OUTSD\n");
outs(4);
} else {
DECODE_PRINTF("OUTSW\n");
outs(2);
}
TRACE_AND_STEP();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x70 - 0x7F
****************************************************************************/
static void x86emuOp_jump_near_cond(u8 op1)
{
s8 offset;
u16 target;
int cond;
/* jump to byte offset if overflow flag is set */
START_OF_INSTR();
cond = x86emu_check_jump_condition(op1 & 0xF);
offset = (s8)fetch_byte_imm();
target = (u16)(M.x86.R_IP + (s16)offset);
DECODE_PRINTF2("%x\n", target);
TRACE_AND_STEP();
if (cond) {
M.x86.R_IP = target;
JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " NEAR COND ");
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x80
****************************************************************************/
static void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg;
uint destoffset;
u8 imm;
u8 destval;
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
#ifdef DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
in the same format, even though the result is that the
above test is done twice. */
switch (rh) {
case 0:
DECODE_PRINTF("ADD\t");
break;
case 1:
DECODE_PRINTF("OR\t");
break;
case 2:
DECODE_PRINTF("ADC\t");
break;
case 3:
DECODE_PRINTF("SBB\t");
break;
case 4:
DECODE_PRINTF("AND\t");
break;
case 5:
DECODE_PRINTF("SUB\t");
break;
case 6:
DECODE_PRINTF("XOR\t");
break;
case 7:
DECODE_PRINTF("CMP\t");
break;
}
}
#endif
/* know operation, decode the mod byte to find the addressing
mode. */
if (mod < 3) {
DECODE_PRINTF("BYTE PTR ");
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
destval = fetch_data_byte(destoffset);
imm = fetch_byte_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_byte_operation[rh]) (destval, imm);
if (rh != 7)
store_data_byte(destoffset, destval);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF(",");
imm = fetch_byte_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_byte_operation[rh]) (*destreg, imm);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x81
****************************************************************************/
static void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
/*
* Weirdo special case instruction format. Part of the opcode
* held below in "RH". Doubly nested case would result, except
* that the decoded instruction
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
#ifdef DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
in the same format, even though the result is that the
above test is done twice. */
switch (rh) {
case 0:
DECODE_PRINTF("ADD\t");
break;
case 1:
DECODE_PRINTF("OR\t");
break;
case 2:
DECODE_PRINTF("ADC\t");
break;
case 3:
DECODE_PRINTF("SBB\t");
break;
case 4:
DECODE_PRINTF("AND\t");
break;
case 5:
DECODE_PRINTF("SUB\t");
break;
case 6:
DECODE_PRINTF("XOR\t");
break;
case 7:
DECODE_PRINTF("CMP\t");
break;
}
}
#endif
/*
* Know operation, decode the mod byte to find the addressing
* mode.
*/
if (mod < 3) {
DECODE_PRINTF("DWORD PTR ");
destoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 destval,imm;
DECODE_PRINTF(",");
destval = fetch_data_long(destoffset);
imm = fetch_long_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_long_operation[rh]) (destval, imm);
if (rh != 7)
store_data_long(destoffset, destval);
} else {
u16 destval,imm;
DECODE_PRINTF(",");
destval = fetch_data_word(destoffset);
imm = fetch_word_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_word_operation[rh]) (destval, imm);
if (rh != 7)
store_data_word(destoffset, destval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg, imm;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF(",");
imm = fetch_long_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_long_operation[rh]) (*destreg, imm);
} else {
u16 *destreg, imm;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
imm = fetch_word_imm();
DECODE_PRINTF2("%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_word_operation[rh]) (*destreg, imm);
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x82
****************************************************************************/
static void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg;
uint destoffset;
u8 imm;
u8 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.
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
#ifdef DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
in the same format, even though the result is that the
above test is done twice. */
switch (rh) {
case 0:
DECODE_PRINTF("ADD\t");
break;
case 1:
DECODE_PRINTF("OR\t");
break;
case 2:
DECODE_PRINTF("ADC\t");
break;
case 3:
DECODE_PRINTF("SBB\t");
break;
case 4:
DECODE_PRINTF("AND\t");
break;
case 5:
DECODE_PRINTF("SUB\t");
break;
case 6:
DECODE_PRINTF("XOR\t");
break;
case 7:
DECODE_PRINTF("CMP\t");
break;
}
}
#endif
/* know operation, decode the mod byte to find the addressing
mode. */
if (mod < 3) {
DECODE_PRINTF("BYTE PTR ");
destoffset = decode_rmXX_address(mod, rl);
destval = fetch_data_byte(destoffset);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_byte_operation[rh]) (destval, imm);
if (rh != 7)
store_data_byte(destoffset, destval);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
imm = fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_byte_operation[rh]) (*destreg, imm);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x83
****************************************************************************/
static void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
/*
* 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.
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
#ifdef DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
in the same format, even though the result is that the
above test is done twice. */
switch (rh) {
case 0:
DECODE_PRINTF("ADD\t");
break;
case 1:
DECODE_PRINTF("OR\t");
break;
case 2:
DECODE_PRINTF("ADC\t");
break;
case 3:
DECODE_PRINTF("SBB\t");
break;
case 4:
DECODE_PRINTF("AND\t");
break;
case 5:
DECODE_PRINTF("SUB\t");
break;
case 6:
DECODE_PRINTF("XOR\t");
break;
case 7:
DECODE_PRINTF("CMP\t");
break;
}
}
#endif
/* know operation, decode the mod byte to find the addressing
mode. */
if (mod < 3) {
DECODE_PRINTF("DWORD PTR ");
destoffset = decode_rmXX_address(mod,rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 destval,imm;
destval = fetch_data_long(destoffset);
imm = (s8) fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_long_operation[rh]) (destval, imm);
if (rh != 7)
store_data_long(destoffset, destval);
} else {
u16 destval,imm;
destval = fetch_data_word(destoffset);
imm = (s8) fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
destval = (*genop_word_operation[rh]) (destval, imm);
if (rh != 7)
store_data_word(destoffset, destval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg, imm;
destreg = DECODE_RM_LONG_REGISTER(rl);
imm = (s8) fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_long_operation[rh]) (*destreg, imm);
} else {
u16 *destreg, imm;
destreg = DECODE_RM_WORD_REGISTER(rl);
imm = (s8) fetch_byte_imm();
DECODE_PRINTF2(",%x\n", imm);
TRACE_AND_STEP();
*destreg = (*genop_word_operation[rh]) (*destreg, imm);
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x84
****************************************************************************/
static void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg, *srcreg;
uint destoffset;
u8 destval;
START_OF_INSTR();
DECODE_PRINTF("TEST\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
destval = fetch_data_byte(destoffset);
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_byte(destval, *srcreg);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_byte(*destreg, *srcreg);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x85
****************************************************************************/
static void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("TEST\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 destval;
u32 *srcreg;
DECODE_PRINTF(",");
destval = fetch_data_long(destoffset);
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_long(destval, *srcreg);
} else {
u16 destval;
u16 *srcreg;
DECODE_PRINTF(",");
destval = fetch_data_word(destoffset);
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_word(destval, *srcreg);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg,*srcreg;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_long(*destreg, *srcreg);
} else {
u16 *destreg,*srcreg;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
test_word(*destreg, *srcreg);
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x86
****************************************************************************/
static void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg, *srcreg;
uint destoffset;
u8 destval;
u8 tmp;
START_OF_INSTR();
DECODE_PRINTF("XCHG\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
destval = fetch_data_byte(destoffset);
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = destval;
destval = tmp;
store_data_byte(destoffset, destval);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = *destreg;
*destreg = tmp;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x87
****************************************************************************/
static void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("XCHG\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *srcreg;
u32 destval,tmp;
destval = fetch_data_long(destoffset);
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = destval;
destval = tmp;
store_data_long(destoffset, destval);
} else {
u16 *srcreg;
u16 destval,tmp;
destval = fetch_data_word(destoffset);
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = destval;
destval = tmp;
store_data_word(destoffset, destval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg,*srcreg;
u32 tmp;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = *destreg;
*destreg = tmp;
} else {
u16 *destreg,*srcreg;
u16 tmp;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = *srcreg;
*srcreg = *destreg;
*destreg = tmp;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x88
****************************************************************************/
static void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg, *srcreg;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
store_data_byte(destoffset, *srcreg);
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x89
****************************************************************************/
static void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *srcreg;
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
store_data_long(destoffset, *srcreg);
} else {
u16 *srcreg;
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
store_data_word(destoffset, *srcreg);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg,*srcreg;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
} else {
u16 *destreg,*srcreg;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8a
****************************************************************************/
static void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u8 *destreg, *srcreg;
uint srcoffset;
u8 srcval;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF(",");
srcoffset = decode_rmXX_address(mod, rl);
srcval = fetch_data_byte(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = srcval;
} else { /* register to register */
destreg = DECODE_RM_BYTE_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_BYTE_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8b
****************************************************************************/
static void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint srcoffset;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg;
u32 srcval;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcoffset = decode_rmXX_address(mod, rl);
srcval = fetch_data_long(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = srcval;
} else {
u16 *destreg;
u16 srcval;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcoffset = decode_rmXX_address(mod, rl);
srcval = fetch_data_word(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = srcval;
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg, *srcreg;
destreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
} else {
u16 *destreg, *srcreg;
destreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8c
****************************************************************************/
static void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u16 *destreg, *srcreg;
uint destoffset;
u16 destval;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF(",");
srcreg = decode_rm_seg_register(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = *srcreg;
store_data_word(destoffset, destval);
} else { /* register to register */
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF(",");
srcreg = decode_rm_seg_register(rh);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8d
****************************************************************************/
static void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("LEA\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
u32 *srcreg = DECODE_RM_LONG_REGISTER(rh);
DECODE_PRINTF(",");
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*srcreg = (u32)destoffset;
} else {
u16 *srcreg = DECODE_RM_WORD_REGISTER(rh);
DECODE_PRINTF(",");
destoffset = decode_rmXX_address(mod, rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*srcreg = (u16)destoffset;
}
}
/* else { undefined. Do nothing. } */
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8e
****************************************************************************/
static void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
u16 *destreg, *srcreg;
uint srcoffset;
u16 srcval;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (mod < 3) {
destreg = decode_rm_seg_register(rh);
DECODE_PRINTF(",");
srcoffset = decode_rmXX_address(mod, rl);
srcval = fetch_data_word(srcoffset);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = srcval;
} else { /* register to register */
destreg = decode_rm_seg_register(rh);
DECODE_PRINTF(",");
srcreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = *srcreg;
}
/*
* 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.
*/
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x8f
****************************************************************************/
static void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1))
{
int mod, rl, rh;
uint destoffset;
START_OF_INSTR();
DECODE_PRINTF("POP\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (rh != 0) {
DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
HALT_SYS();
}
if (mod < 3) {
destoffset = decode_rmXX_address(mod, rl);
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 destval;
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = pop_long();
store_data_long(destoffset, destval);
} else {
u16 destval;
DECODE_PRINTF("\n");
TRACE_AND_STEP();
destval = pop_word();
store_data_word(destoffset, destval);
}
} else { /* register to register */
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *destreg;
destreg = DECODE_RM_LONG_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = pop_long();
} else {
u16 *destreg;
destreg = DECODE_RM_WORD_REGISTER(rl);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
*destreg = pop_word();
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x90
****************************************************************************/
static void x86emuOp_nop(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("NOP\n");
TRACE_AND_STEP();
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x91-0x97
****************************************************************************/
static void x86emuOp_xchg_word_AX_register(u8 X86EMU_UNUSED(op1))
{
u32 tmp;
op1 &= 0x7;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
u32 *reg32;
DECODE_PRINTF("XCHG\tEAX,");
reg32 = DECODE_RM_LONG_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = M.x86.R_EAX;
M.x86.R_EAX = *reg32;
*reg32 = tmp;
} else {
u16 *reg16;
DECODE_PRINTF("XCHG\tAX,");
reg16 = DECODE_RM_WORD_REGISTER(op1);
DECODE_PRINTF("\n");
TRACE_AND_STEP();
tmp = M.x86.R_AX;
M.x86.R_AX = *reg16;
*reg16 = (u16)tmp;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x98
****************************************************************************/
static void x86emuOp_cbw(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("CWDE\n");
} else {
DECODE_PRINTF("CBW\n");
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
if (M.x86.R_AX & 0x8000) {
M.x86.R_EAX |= 0xffff0000;
} else {
M.x86.R_EAX &= 0x0000ffff;
}
} else {
if (M.x86.R_AL & 0x80) {
M.x86.R_AH = 0xff;
} else {
M.x86.R_AH = 0x0;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x99
****************************************************************************/
static void x86emuOp_cwd(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("CDQ\n");
} else {
DECODE_PRINTF("CWD\n");
}
DECODE_PRINTF("CWD\n");
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
if (M.x86.R_EAX & 0x80000000) {
M.x86.R_EDX = 0xffffffff;
} else {
M.x86.R_EDX = 0x0;
}
} else {
if (M.x86.R_AX & 0x8000) {
M.x86.R_DX = 0xffff;
} else {
M.x86.R_DX = 0x0;
}
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9a
****************************************************************************/
static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
{
u32 farseg, faroff;
START_OF_INSTR();
DECODE_PRINTF("CALL\t");
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
faroff = fetch_long_imm();
farseg = fetch_word_imm();
} else {
faroff = fetch_word_imm();
farseg = fetch_word_imm();
}
DECODE_PRINTF2("%04x:", farseg);
DECODE_PRINTF2("%04x\n", faroff);
CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
/* XXX
*
* Hooked interrupt vectors calling into our "BIOS" will cause
* problems unless all intersegment stuff is checked for BIOS
* access. Check needed here. For moment, let it alone.
*/
TRACE_AND_STEP();
push_word(M.x86.R_CS);
M.x86.R_CS = farseg;
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
push_long(M.x86.R_EIP);
} else {
push_word(M.x86.R_IP);
}
M.x86.R_EIP = faroff & 0xffff;
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9b
****************************************************************************/
static void x86emuOp_wait(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("WAIT");
TRACE_AND_STEP();
/* NADA. */
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9c
****************************************************************************/
static void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1))
{
u32 flags;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("PUSHFD\n");
} else {
DECODE_PRINTF("PUSHF\n");
}
TRACE_AND_STEP();
/* clear out *all* bits not representing flags, and turn on real bits */
flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
push_long(flags);
} else {
push_word((u16)flags);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9d
****************************************************************************/
static void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("POPFD\n");
} else {
DECODE_PRINTF("POPF\n");
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
M.x86.R_EFLG = pop_long();
} else {
M.x86.R_FLG = pop_word();
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9e
****************************************************************************/
static void x86emuOp_sahf(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("SAHF\n");
TRACE_AND_STEP();
/* clear the lower bits of the flag register */
M.x86.R_FLG &= 0xffffff00;
/* or in the AH register into the flags register */
M.x86.R_FLG |= M.x86.R_AH;
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0x9f
****************************************************************************/
static void x86emuOp_lahf(u8 X86EMU_UNUSED(op1))
{
START_OF_INSTR();
DECODE_PRINTF("LAHF\n");
TRACE_AND_STEP();
M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff);
/*undocumented TC++ behavior??? Nope. It's documented, but
you have too look real hard to notice it. */
M.x86.R_AH |= 0x2;
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa0
****************************************************************************/
static void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1))
{
u16 offset;
START_OF_INSTR();
DECODE_PRINTF("MOV\tAL,");
offset = fetch_word_imm();
DECODE_PRINTF2("[%04x]\n", offset);
TRACE_AND_STEP();
M.x86.R_AL = fetch_data_byte(offset);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa1
****************************************************************************/
static void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1))
{
u16 offset;
START_OF_INSTR();
offset = fetch_word_imm();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset);
} else {
DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset);
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
M.x86.R_EAX = fetch_data_long(offset);
} else {
M.x86.R_AX = fetch_data_word(offset);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa2
****************************************************************************/
static void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1))
{
u16 offset;
START_OF_INSTR();
DECODE_PRINTF("MOV\t");
offset = fetch_word_imm();
DECODE_PRINTF2("[%04x],AL\n", offset);
TRACE_AND_STEP();
store_data_byte(offset, M.x86.R_AL);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa3
****************************************************************************/
static void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1))
{
u16 offset;
START_OF_INSTR();
offset = fetch_word_imm();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset);
} else {
DECODE_PRINTF2("MOV\t[%04x],AX\n", offset);
}
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
store_data_long(offset, M.x86.R_EAX);
} else {
store_data_word(offset, M.x86.R_AX);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa4
****************************************************************************/
static void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1))
{
u8 val;
u32 count;
int inc;
START_OF_INSTR();
DECODE_PRINTF("MOVS\tBYTE\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -1;
else
inc = 1;
TRACE_AND_STEP();
count = 1;
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* don't care whether REPE or REPNE */
/* move them until (E)CX is ZERO. */
count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
M.x86.R_CX = 0;
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX = 0;
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
}
while (count--) {
val = fetch_data_byte(M.x86.R_SI);
store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val);
M.x86.R_SI += inc;
M.x86.R_DI += inc;
if (M.x86.intr & INTR_HALTED)
break;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa5
****************************************************************************/
static void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1))
{
u32 val;
int inc;
u32 count;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("MOVS\tDWORD\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -4;
else
inc = 4;
} else {
DECODE_PRINTF("MOVS\tWORD\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -2;
else
inc = 2;
}
TRACE_AND_STEP();
count = 1;
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* don't care whether REPE or REPNE */
/* move them until (E)CX is ZERO. */
count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
M.x86.R_CX = 0;
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX = 0;
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
}
while (count--) {
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
val = fetch_data_long(M.x86.R_SI);
store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val);
} else {
val = fetch_data_word(M.x86.R_SI);
store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val);
}
M.x86.R_SI += inc;
M.x86.R_DI += inc;
if (M.x86.intr & INTR_HALTED)
break;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa6
****************************************************************************/
static void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1))
{
s8 val1, val2;
int inc;
START_OF_INSTR();
DECODE_PRINTF("CMPS\tBYTE\n");
TRACE_AND_STEP();
if (ACCESS_FLAG(F_DF)) /* down */
inc = -1;
else
inc = 1;
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* REPE */
/* move them until (E)CX is ZERO. */
while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
val1 = fetch_data_byte(M.x86.R_SI);
val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
cmp_byte(val1, val2);
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX -= 1;
else
M.x86.R_CX -= 1;
M.x86.R_SI += inc;
M.x86.R_DI += inc;
if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break;
if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
if (M.x86.intr & INTR_HALTED)
break;
}
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
} else {
val1 = fetch_data_byte(M.x86.R_SI);
val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
cmp_byte(val1, val2);
M.x86.R_SI += inc;
M.x86.R_DI += inc;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa7
****************************************************************************/
static void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1))
{
u32 val1,val2;
int inc;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("CMPS\tDWORD\n");
inc = 4;
} else {
DECODE_PRINTF("CMPS\tWORD\n");
inc = 2;
}
if (ACCESS_FLAG(F_DF)) /* down */
inc = -inc;
TRACE_AND_STEP();
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* REPE */
/* move them until (E)CX is ZERO. */
while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
val1 = fetch_data_long(M.x86.R_SI);
val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
cmp_long(val1, val2);
} else {
val1 = fetch_data_word(M.x86.R_SI);
val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
cmp_word((u16)val1, (u16)val2);
}
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX -= 1;
else
M.x86.R_CX -= 1;
M.x86.R_SI += inc;
M.x86.R_DI += inc;
if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break;
if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
if (M.x86.intr & INTR_HALTED)
break;
}
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
} else {
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
val1 = fetch_data_long(M.x86.R_SI);
val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
cmp_long(val1, val2);
} else {
val1 = fetch_data_word(M.x86.R_SI);
val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
cmp_word((u16)val1, (u16)val2);
}
M.x86.R_SI += inc;
M.x86.R_DI += inc;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa8
****************************************************************************/
static void x86emuOp_test_AL_IMM(u8 X86EMU_UNUSED(op1))
{
int imm;
START_OF_INSTR();
DECODE_PRINTF("TEST\tAL,");
imm = fetch_byte_imm();
DECODE_PRINTF2("%04x\n", imm);
TRACE_AND_STEP();
test_byte(M.x86.R_AL, (u8)imm);
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xa9
****************************************************************************/
static void x86emuOp_test_AX_IMM(u8 X86EMU_UNUSED(op1))
{
u32 srcval;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("TEST\tEAX,");
srcval = fetch_long_imm();
} else {
DECODE_PRINTF("TEST\tAX,");
srcval = fetch_word_imm();
}
DECODE_PRINTF2("%x\n", srcval);
TRACE_AND_STEP();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
test_long(M.x86.R_EAX, srcval);
} else {
test_word(M.x86.R_AX, (u16)srcval);
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xaa
****************************************************************************/
static void x86emuOp_stos_byte(u8 X86EMU_UNUSED(op1))
{
int inc;
START_OF_INSTR();
DECODE_PRINTF("STOS\tBYTE\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -1;
else
inc = 1;
TRACE_AND_STEP();
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* don't care whether REPE or REPNE */
/* move them until (E)CX is ZERO. */
while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX -= 1;
else
M.x86.R_CX -= 1;
M.x86.R_DI += inc;
if (M.x86.intr & INTR_HALTED)
break;
}
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
} else {
store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
M.x86.R_DI += inc;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xab
****************************************************************************/
static void x86emuOp_stos_word(u8 X86EMU_UNUSED(op1))
{
int inc;
u32 count;
START_OF_INSTR();
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
DECODE_PRINTF("STOS\tDWORD\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -4;
else
inc = 4;
} else {
DECODE_PRINTF("STOS\tWORD\n");
if (ACCESS_FLAG(F_DF)) /* down */
inc = -2;
else
inc = 2;
}
TRACE_AND_STEP();
count = 1;
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* don't care whether REPE or REPNE */
/* move them until (E)CX is ZERO. */
count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
M.x86.R_CX = 0;
if (M.x86.mode & SYSMODE_32BIT_REP)
M.x86.R_ECX = 0;
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
}
while (count--) {
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
store_data_long_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_EAX);
} else {
store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX);
}
M.x86.R_DI += inc;
if (M.x86.intr & INTR_HALTED)
break;
}
DECODE_CLEAR_SEGOVR();
END_OF_INSTR();
}
/****************************************************************************
REMARKS:
Handles opcode 0xac
****************************************************************************/
static void x86emuOp_lods_byte(u8 X86EMU_UNUSED(op1))
{
int inc;
START_OF_INSTR();
DECODE_PRINTF("LODS\tBYTE\n");
TRACE_AND_STEP();
if (ACCESS_FLAG(F_DF)) /* down */
inc = -1;
else
inc = 1;
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
/* don't care whether REPE or REPNE */