diff options
| author | Jason Jin <Jason.jin@freescale.com> | 2007-07-06 08:34:56 +0800 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2007-08-06 01:28:15 +0200 | 
| commit | ece92f85053b8df613edcf05b26a416cbc3d629c (patch) | |
| tree | 2d3389882d0655781183c2fd655dc6746c5eeea1 /drivers/bios_emulator/x86emu | |
| parent | 5072188acabde3178fac7f5a597150e6e74fd40c (diff) | |
| download | olio-uboot-2014.01-ece92f85053b8df613edcf05b26a416cbc3d629c.tar.xz olio-uboot-2014.01-ece92f85053b8df613edcf05b26a416cbc3d629c.zip | |
This is a BIOS emulator, porting from SciTech for u-boot, mainly for
ATI video card BIOS. and can be used for x86 code emulation by some
modifications.
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
Diffstat (limited to 'drivers/bios_emulator/x86emu')
| -rw-r--r-- | drivers/bios_emulator/x86emu/debug.c | 461 | ||||
| -rw-r--r-- | drivers/bios_emulator/x86emu/decode.c | 1148 | ||||
| -rw-r--r-- | drivers/bios_emulator/x86emu/ops.c | 5431 | ||||
| -rw-r--r-- | drivers/bios_emulator/x86emu/ops2.c | 1770 | ||||
| -rw-r--r-- | drivers/bios_emulator/x86emu/prim_ops.c | 2446 | ||||
| -rw-r--r-- | drivers/bios_emulator/x86emu/sys.c | 322 | 
6 files changed, 11578 insertions, 0 deletions
| diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c new file mode 100644 index 000000000..0f58a6963 --- /dev/null +++ b/drivers/bios_emulator/x86emu/debug.c @@ -0,0 +1,461 @@ +/**************************************************************************** +* +*                       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 contains the code to handle debugging of the +*               emulator. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" +#include <stdarg.h> + +/*----------------------------- Implementation ----------------------------*/ + +#ifdef DEBUG + +static void print_encoded_bytes(u16 s, u16 o); +static void print_decoded_instruction(void); +static int parse_line(char *s, int *ps, int *n); + +/* should look something like debug's output. */ +void X86EMU_trace_regs(void) +{ +	if (DEBUG_TRACE()) { +		x86emu_dump_regs(); +	} +	if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) { +		printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); +		print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); +		print_decoded_instruction(); +	} +} + +void X86EMU_trace_xregs(void) +{ +	if (DEBUG_TRACE()) { +		x86emu_dump_xregs(); +	} +} + +void x86emu_just_disassemble(void) +{ +	/* +	 * This routine called if the flag DEBUG_DISASSEMBLE is set kind +	 * of a hack! +	 */ +	printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); +	print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); +	print_decoded_instruction(); +} + +static void disassemble_forward(u16 seg, u16 off, int n) +{ +	X86EMU_sysEnv tregs; +	int i; +	u8 op1; +	/* +	 * hack, hack, hack.  What we do is use the exact machinery set up +	 * for execution, except that now there is an additional state +	 * flag associated with the "execution", and we are using a copy +	 * of the register struct.  All the major opcodes, once fully +	 * decoded, have the following two steps: TRACE_REGS(r,m); +	 * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to +	 * the preprocessor.  The TRACE_REGS macro expands to: +	 * +	 * if (debug&DEBUG_DISASSEMBLE) +	 *     {just_disassemble(); goto EndOfInstruction;} +	 *     if (debug&DEBUG_TRACE) trace_regs(r,m); +	 * +	 * ......  and at the last line of the routine. +	 * +	 * EndOfInstruction: end_instr(); +	 * +	 * Up to the point where TRACE_REG is expanded, NO modifications +	 * are done to any register EXCEPT the IP register, for fetch and +	 * decoding purposes. +	 * +	 * This was done for an entirely different reason, but makes a +	 * nice way to get the system to help debug codes. +	 */ +	tregs = M; +	tregs.x86.R_IP = off; +	tregs.x86.R_CS = seg; + +	/* reset the decoding buffers */ +	tregs.x86.enc_str_pos = 0; +	tregs.x86.enc_pos = 0; + +	/* turn on the "disassemble only, no execute" flag */ +	tregs.x86.debug |= DEBUG_DISASSEMBLE_F; + +	/* DUMP NEXT n instructions to screen in straight_line fashion */ +	/* +	 * This looks like the regular instruction fetch stream, except +	 * that when this occurs, each fetched opcode, upon seeing the +	 * DEBUG_DISASSEMBLE flag set, exits immediately after decoding +	 * the instruction.  XXX --- CHECK THAT MEM IS NOT AFFECTED!!! +	 * Note the use of a copy of the register structure... +	 */ +	for (i = 0; i < n; i++) { +		op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); +		(x86emu_optab[op1]) (op1); +	} +	/* end major hack mode. */ +} + +void x86emu_check_ip_access(void) +{ +	/* NULL as of now */ +} + +void x86emu_check_sp_access(void) +{ +} + +void x86emu_check_mem_access(u32 dummy) +{ +	/*  check bounds, etc */ +} + +void x86emu_check_data_access(uint dummy1, uint dummy2) +{ +	/*  check bounds, etc */ +} + +void x86emu_inc_decoded_inst_len(int x) +{ +	M.x86.enc_pos += x; +} + +void x86emu_decode_printf(char *x) +{ +	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x); +	M.x86.enc_str_pos += strlen(x); +} + +void x86emu_decode_printf2(char *x, int y) +{ +	char temp[100]; +	sprintf(temp, x, y); +	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp); +	M.x86.enc_str_pos += strlen(temp); +} + +void x86emu_end_instr(void) +{ +	M.x86.enc_str_pos = 0; +	M.x86.enc_pos = 0; +} + +static void print_encoded_bytes(u16 s, u16 o) +{ +	int i; +	char buf1[64]; +	for (i = 0; i < M.x86.enc_pos; i++) { +		sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i)); +	} +	printk("%-20s", buf1); +} + +static void print_decoded_instruction(void) +{ +	printk("%s", M.x86.decoded_buf); +} + +void x86emu_print_int_vect(u16 iv) +{ +	u16 seg, off; + +	if (iv > 256) +		return; +	seg = fetch_data_word_abs(0, iv * 4); +	off = fetch_data_word_abs(0, iv * 4 + 2); +	printk("%04x:%04x ", seg, off); +} + +void X86EMU_dump_memory(u16 seg, u16 off, u32 amt) +{ +	u32 start = off & 0xfffffff0; +	u32 end = (off + 16) & 0xfffffff0; +	u32 i; +	u32 current; + +	current = start; +	while (end <= off + amt) { +		printk("%04x:%04x ", seg, start); +		for (i = start; i < off; i++) +			printk("   "); +		for (; i < end; i++) +			printk("%02x ", fetch_data_byte_abs(seg, i)); +		printk("\n"); +		start = end; +		end = start + 16; +	} +} + +void x86emu_single_step(void) +{ +	char s[1024]; +	int ps[10]; +	int ntok; +	int cmd; +	int done; +	int segment; +	int offset; +	static int breakpoint; +	static int noDecode = 1; + +	char *p; + +	if (DEBUG_BREAK()) { +		if (M.x86.saved_ip != breakpoint) { +			return; +		} else { +			M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; +			M.x86.debug |= DEBUG_TRACE_F; +			M.x86.debug &= ~DEBUG_BREAK_F; +			print_decoded_instruction(); +			X86EMU_trace_regs(); +		} +	} +	done = 0; +	offset = M.x86.saved_ip; +	while (!done) { +		printk("-"); +		cmd = parse_line(s, ps, &ntok); +		switch (cmd) { +		case 'u': +			disassemble_forward(M.x86.saved_cs, (u16) offset, 10); +			break; +		case 'd': +			if (ntok == 2) { +				segment = M.x86.saved_cs; +				offset = ps[1]; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} else if (ntok == 3) { +				segment = ps[1]; +				offset = ps[2]; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} else { +				segment = M.x86.saved_cs; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} +			break; +		case 'c': +			M.x86.debug ^= DEBUG_TRACECALL_F; +			break; +		case 's': +			M.x86.debug ^= +			    DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; +			break; +		case 'r': +			X86EMU_trace_regs(); +			break; +		case 'x': +			X86EMU_trace_xregs(); +			break; +		case 'g': +			if (ntok == 2) { +				breakpoint = ps[1]; +				if (noDecode) { +					M.x86.debug |= DEBUG_DECODE_NOPRINT_F; +				} else { +					M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; +				} +				M.x86.debug &= ~DEBUG_TRACE_F; +				M.x86.debug |= DEBUG_BREAK_F; +				done = 1; +			} +			break; +		case 'q': +			M.x86.debug |= DEBUG_EXIT; +			return; +		case 'P': +			noDecode = (noDecode) ? 0 : 1; +			printk("Toggled decoding to %s\n", +			       (noDecode) ? "FALSE" : "TRUE"); +			break; +		case 't': +		case 0: +			done = 1; +			break; +		} +	} +} + +int X86EMU_trace_on(void) +{ +	return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; +} + +int X86EMU_trace_off(void) +{ +	return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); +} + +static int parse_line(char *s, int *ps, int *n) +{ +	int cmd; + +	*n = 0; +	while (*s == ' ' || *s == '\t') +		s++; +	ps[*n] = *s; +	switch (*s) { +	case '\n': +		*n += 1; +		return 0; +	default: +		cmd = *s; +		*n += 1; +	} + +	while (1) { +		while (*s != ' ' && *s != '\t' && *s != '\n') +			s++; + +		if (*s == '\n') +			return cmd; + +		while (*s == ' ' || *s == '\t') +			s++; + +		*n += 1; +	} +} + +#endif				/* DEBUG */ + +void x86emu_dump_regs(void) +{ +	printk("\tAX=%04x  ", M.x86.R_AX); +	printk("BX=%04x  ", M.x86.R_BX); +	printk("CX=%04x  ", M.x86.R_CX); +	printk("DX=%04x  ", M.x86.R_DX); +	printk("SP=%04x  ", M.x86.R_SP); +	printk("BP=%04x  ", M.x86.R_BP); +	printk("SI=%04x  ", M.x86.R_SI); +	printk("DI=%04x\n", M.x86.R_DI); +	printk("\tDS=%04x  ", M.x86.R_DS); +	printk("ES=%04x  ", M.x86.R_ES); +	printk("SS=%04x  ", M.x86.R_SS); +	printk("CS=%04x  ", M.x86.R_CS); +	printk("IP=%04x   ", M.x86.R_IP); +	if (ACCESS_FLAG(F_OF)) +		printk("OV ");	/* CHECKED... */ +	else +		printk("NV "); +	if (ACCESS_FLAG(F_DF)) +		printk("DN "); +	else +		printk("UP "); +	if (ACCESS_FLAG(F_IF)) +		printk("EI "); +	else +		printk("DI "); +	if (ACCESS_FLAG(F_SF)) +		printk("NG "); +	else +		printk("PL "); +	if (ACCESS_FLAG(F_ZF)) +		printk("ZR "); +	else +		printk("NZ "); +	if (ACCESS_FLAG(F_AF)) +		printk("AC "); +	else +		printk("NA "); +	if (ACCESS_FLAG(F_PF)) +		printk("PE "); +	else +		printk("PO "); +	if (ACCESS_FLAG(F_CF)) +		printk("CY "); +	else +		printk("NC "); +	printk("\n"); +} + +void x86emu_dump_xregs(void) +{ +	printk("\tEAX=%08x  ", M.x86.R_EAX); +	printk("EBX=%08x  ", M.x86.R_EBX); +	printk("ECX=%08x  ", M.x86.R_ECX); +	printk("EDX=%08x  \n", M.x86.R_EDX); +	printk("\tESP=%08x  ", M.x86.R_ESP); +	printk("EBP=%08x  ", M.x86.R_EBP); +	printk("ESI=%08x  ", M.x86.R_ESI); +	printk("EDI=%08x\n", M.x86.R_EDI); +	printk("\tDS=%04x  ", M.x86.R_DS); +	printk("ES=%04x  ", M.x86.R_ES); +	printk("SS=%04x  ", M.x86.R_SS); +	printk("CS=%04x  ", M.x86.R_CS); +	printk("EIP=%08x\n\t", M.x86.R_EIP); +	if (ACCESS_FLAG(F_OF)) +		printk("OV ");	/* CHECKED... */ +	else +		printk("NV "); +	if (ACCESS_FLAG(F_DF)) +		printk("DN "); +	else +		printk("UP "); +	if (ACCESS_FLAG(F_IF)) +		printk("EI "); +	else +		printk("DI "); +	if (ACCESS_FLAG(F_SF)) +		printk("NG "); +	else +		printk("PL "); +	if (ACCESS_FLAG(F_ZF)) +		printk("ZR "); +	else +		printk("NZ "); +	if (ACCESS_FLAG(F_AF)) +		printk("AC "); +	else +		printk("NA "); +	if (ACCESS_FLAG(F_PF)) +		printk("PE "); +	else +		printk("PO "); +	if (ACCESS_FLAG(F_CF)) +		printk("CY "); +	else +		printk("NC "); +	printk("\n"); +} diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c new file mode 100644 index 000000000..b4dbb2079 --- /dev/null +++ b/drivers/bios_emulator/x86emu/decode.c @@ -0,0 +1,1148 @@ +/**************************************************************************** +* +*                       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 which are related to +*               instruction decoding and accessess of immediate data via IP.  etc. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +REMARKS: +Handles any pending asychronous interrupts. +****************************************************************************/ +static void x86emu_intr_handle(void) +{ +    u8  intno; + +    if (M.x86.intr & INTR_SYNCH) { +        intno = M.x86.intno; +        if (_X86EMU_intrTab[intno]) { +            (*_X86EMU_intrTab[intno])(intno); +        } else { +            push_word((u16)M.x86.R_FLG); +            CLEAR_FLAG(F_IF); +            CLEAR_FLAG(F_TF); +            push_word(M.x86.R_CS); +            M.x86.R_CS = mem_access_word(intno * 4 + 2); +            push_word(M.x86.R_IP); +            M.x86.R_IP = mem_access_word(intno * 4); +            M.x86.intr = 0; +        } +    } +} + +/**************************************************************************** +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( +    u8 intrnum) +{ +    M.x86.intno = intrnum; +    M.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(void) +{ +    u8 op1; + +    M.x86.intr = 0; +    DB(x86emu_end_instr();) + +    for (;;) { +DB(     if (CHECK_IP_FETCH()) +            x86emu_check_ip_access();) +        /* If debugging, save the IP and CS values. */ +        SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); +        INC_DECODED_INST_LEN(1); +        if (M.x86.intr) { +            if (M.x86.intr & INTR_HALTED) { +DB(             if (M.x86.R_SP != 0) { +                    printk("halted\n"); +                    X86EMU_trace_regs(); +                    } +                else { +                    if (M.x86.debug) +                        printk("Service completed successfully\n"); +                    }) +                return; +            } +            if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) || +                !ACCESS_FLAG(F_IF)) { +                x86emu_intr_handle(); +            } +        } +        op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); +        (*x86emu_optab[op1])(op1); +        if (M.x86.debug & DEBUG_EXIT) { +            M.x86.debug &= ~DEBUG_EXIT; +            return; +        } +    } +} + +/**************************************************************************** +REMARKS: +Halts the system by setting the halted system flag. +****************************************************************************/ +void X86EMU_halt_sys(void) +{ +    M.x86.intr |= INTR_HALTED; +} + +/**************************************************************************** +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 (*sys_rdb) is already inline! +****************************************************************************/ +void fetch_decode_modrm( +    int *mod, +    int *regh, +    int *regl) +{ +    int fetched; + +DB( if (CHECK_IP_FETCH()) +        x86emu_check_ip_access();) +    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); +    INC_DECODED_INST_LEN(1); +    *mod  = (fetched >> 6) & 0x03; +    *regh = (fetched >> 3) & 0x07; +    *regl = (fetched >> 0) & 0x07; +} + +/**************************************************************************** +RETURNS: +Immediate byte 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 (*sys_rdb) is already inline! +****************************************************************************/ +u8 fetch_byte_imm(void) +{ +    u8 fetched; + +DB( if (CHECK_IP_FETCH()) +        x86emu_check_ip_access();) +    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); +    INC_DECODED_INST_LEN(1); +    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 (*sys_rdw) is already inline! +****************************************************************************/ +u16 fetch_word_imm(void) +{ +    u16 fetched; + +DB( if (CHECK_IP_FETCH()) +        x86emu_check_ip_access();) +    fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); +    M.x86.R_IP += 2; +    INC_DECODED_INST_LEN(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 (*sys_rdw) is already inline! +****************************************************************************/ +u32 fetch_long_imm(void) +{ +    u32 fetched; + +DB( if (CHECK_IP_FETCH()) +        x86emu_check_ip_access();) +    fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); +    M.x86.R_IP += 4; +    INC_DECODED_INST_LEN(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-varible M.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 absense of override) + +Each of the above 7 items are handled with a bit in the mode field. +****************************************************************************/ +_INLINE u32 get_data_segment(void) +{ +#define GET_SEGMENT(segment) +    switch (M.x86.mode & SYSMODE_SEGMASK) { +      case 0:                   /* default case: use ds register */ +      case SYSMODE_SEGOVR_DS: +      case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: +        return  M.x86.R_DS; +      case SYSMODE_SEG_DS_SS:   /* non-overridden, use ss register */ +        return  M.x86.R_SS; +      case SYSMODE_SEGOVR_CS: +      case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: +        return  M.x86.R_CS; +      case SYSMODE_SEGOVR_ES: +      case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: +        return  M.x86.R_ES; +      case SYSMODE_SEGOVR_FS: +      case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: +        return  M.x86.R_FS; +      case SYSMODE_SEGOVR_GS: +      case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: +        return  M.x86.R_GS; +      case SYSMODE_SEGOVR_SS: +      case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: +        return  M.x86.R_SS; +      default: +#ifdef  DEBUG +        printk("error: should not happen:  multiple overrides.\n"); +#endif +        HALT_SYS(); +        return 0; +    } +} + +/**************************************************************************** +PARAMETERS: +offset  - Offset to load data from + +RETURNS: +Byte value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u8 fetch_data_byte( +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    return (*sys_rdb)((get_data_segment() << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset  - Offset to load data from + +RETURNS: +Word value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u16 fetch_data_word( +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    return (*sys_rdw)((get_data_segment() << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset  - Offset to load data from + +RETURNS: +Long value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u32 fetch_data_long( +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    return (*sys_rdl)((get_data_segment() << 4) + 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 (*sys_rdX) is already inline! +****************************************************************************/ +u8 fetch_data_byte_abs( +    uint segment, +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    return (*sys_rdb)(((u32)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 (*sys_rdX) is already inline! +****************************************************************************/ +u16 fetch_data_word_abs( +    uint segment, +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    return (*sys_rdw)(((u32)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 (*sys_rdX) is already inline! +****************************************************************************/ +u32 fetch_data_long_abs( +    uint segment, +    uint offset) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    return (*sys_rdl)(((u32)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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_byte( +    uint offset, +    u8 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    (*sys_wrb)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_word( +    uint offset, +    u16 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    (*sys_wrw)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_long( +    uint offset, +    u32 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access((u16)get_data_segment(), offset); +#endif +    (*sys_wrl)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_byte_abs( +    uint segment, +    uint offset, +    u8 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    (*sys_wrb)(((u32)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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_word_abs( +    uint segment, +    uint offset, +    u16 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    (*sys_wrw)(((u32)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 (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_long_abs( +    uint segment, +    uint offset, +    u32 val) +{ +#ifdef DEBUG +    if (CHECK_DATA_ACCESS()) +        x86emu_check_data_access(segment, offset); +#endif +    (*sys_wrl)(((u32)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. +****************************************************************************/ +u8* decode_rm_byte_register( +    int reg) +{ +    switch (reg) { +      case 0: +        DECODE_PRINTF("AL"); +        return &M.x86.R_AL; +      case 1: +        DECODE_PRINTF("CL"); +        return &M.x86.R_CL; +      case 2: +        DECODE_PRINTF("DL"); +        return &M.x86.R_DL; +      case 3: +        DECODE_PRINTF("BL"); +        return &M.x86.R_BL; +      case 4: +        DECODE_PRINTF("AH"); +        return &M.x86.R_AH; +      case 5: +        DECODE_PRINTF("CH"); +        return &M.x86.R_CH; +      case 6: +        DECODE_PRINTF("DH"); +        return &M.x86.R_DH; +      case 7: +        DECODE_PRINTF("BH"); +        return &M.x86.R_BH; +    } +    HALT_SYS(); +    return NULL;                /* NOT REACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +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.  Also enables the decoding of instructions. +****************************************************************************/ +u16* decode_rm_word_register( +    int reg) +{ +    switch (reg) { +      case 0: +        DECODE_PRINTF("AX"); +        return &M.x86.R_AX; +      case 1: +        DECODE_PRINTF("CX"); +        return &M.x86.R_CX; +      case 2: +        DECODE_PRINTF("DX"); +        return &M.x86.R_DX; +      case 3: +        DECODE_PRINTF("BX"); +        return &M.x86.R_BX; +      case 4: +        DECODE_PRINTF("SP"); +        return &M.x86.R_SP; +      case 5: +        DECODE_PRINTF("BP"); +        return &M.x86.R_BP; +      case 6: +        DECODE_PRINTF("SI"); +        return &M.x86.R_SI; +      case 7: +        DECODE_PRINTF("DI"); +        return &M.x86.R_DI; +    } +    HALT_SYS(); +    return NULL;                /* NOTREACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +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 dword operands.  Also enables the decoding of instructions. +****************************************************************************/ +u32* decode_rm_long_register( +    int reg) +{ +    switch (reg) { +      case 0: +        DECODE_PRINTF("EAX"); +        return &M.x86.R_EAX; +      case 1: +        DECODE_PRINTF("ECX"); +        return &M.x86.R_ECX; +      case 2: +        DECODE_PRINTF("EDX"); +        return &M.x86.R_EDX; +      case 3: +        DECODE_PRINTF("EBX"); +        return &M.x86.R_EBX; +      case 4: +        DECODE_PRINTF("ESP"); +        return &M.x86.R_ESP; +      case 5: +        DECODE_PRINTF("EBP"); +        return &M.x86.R_EBP; +      case 6: +        DECODE_PRINTF("ESI"); +        return &M.x86.R_ESI; +      case 7: +        DECODE_PRINTF("EDI"); +        return &M.x86.R_EDI; +    } +    HALT_SYS(); +    return NULL;                /* NOTREACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +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. +****************************************************************************/ +u16* decode_rm_seg_register( +    int reg) +{ +    switch (reg) { +      case 0: +        DECODE_PRINTF("ES"); +        return &M.x86.R_ES; +      case 1: +        DECODE_PRINTF("CS"); +        return &M.x86.R_CS; +      case 2: +        DECODE_PRINTF("SS"); +        return &M.x86.R_SS; +      case 3: +        DECODE_PRINTF("DS"); +        return &M.x86.R_DS; +      case 4: +        DECODE_PRINTF("FS"); +        return &M.x86.R_FS; +      case 5: +        DECODE_PRINTF("GS"); +        return &M.x86.R_GS; +      case 6: +      case 7: +        DECODE_PRINTF("ILLEGAL SEGREG"); +        break; +    } +    HALT_SYS(); +    return NULL;                /* NOT REACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +PARAMETERS: +scale - scale value of SIB byte +index - index value of SIB byte + +RETURNS: +Value of scale * index + +REMARKS: +Decodes scale/index of SIB byte and returns relevant offset part of +effective address. +****************************************************************************/ +unsigned decode_sib_si( +    int scale, +    int index) +{ +    scale = 1 << scale; +    if (scale > 1) { +        DECODE_PRINTF2("[%d*", scale); +    } else { +        DECODE_PRINTF("["); +    } +    switch (index) { +      case 0: +        DECODE_PRINTF("EAX]"); +        return M.x86.R_EAX * index; +      case 1: +        DECODE_PRINTF("ECX]"); +        return M.x86.R_ECX * index; +      case 2: +        DECODE_PRINTF("EDX]"); +        return M.x86.R_EDX * index; +      case 3: +        DECODE_PRINTF("EBX]"); +        return M.x86.R_EBX * index; +      case 4: +        DECODE_PRINTF("0]"); +        return 0; +      case 5: +        DECODE_PRINTF("EBP]"); +        return M.x86.R_EBP * index; +      case 6: +        DECODE_PRINTF("ESI]"); +        return M.x86.R_ESI * index; +      case 7: +        DECODE_PRINTF("EDI]"); +        return M.x86.R_EDI * index; +    } +    HALT_SYS(); +    return 0;                   /* NOT REACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +PARAMETERS: +mod - MOD value of preceding ModR/M byte + +RETURNS: +Offset in memory for the address decoding + +REMARKS: +Decodes SIB addressing byte and returns calculated effective address. +****************************************************************************/ +unsigned decode_sib_address( +    int mod) +{ +    int sib   = fetch_byte_imm(); +    int ss    = (sib >> 6) & 0x03; +    int index = (sib >> 3) & 0x07; +    int base  = sib & 0x07; +    int offset = 0; +    int displacement; + +    switch (base) { +      case 0: +        DECODE_PRINTF("[EAX]"); +        offset = M.x86.R_EAX; +        break; +      case 1: +        DECODE_PRINTF("[ECX]"); +        offset = M.x86.R_ECX; +        break; +      case 2: +        DECODE_PRINTF("[EDX]"); +        offset = M.x86.R_EDX; +        break; +      case 3: +        DECODE_PRINTF("[EBX]"); +        offset = M.x86.R_EBX; +        break; +      case 4: +        DECODE_PRINTF("[ESP]"); +        offset = M.x86.R_ESP; +        break; +      case 5: +        switch (mod) { +          case 0: +            displacement = (s32)fetch_long_imm(); +            DECODE_PRINTF2("[%d]", displacement); +            offset = displacement; +            break; +          case 1: +            displacement = (s8)fetch_byte_imm(); +            DECODE_PRINTF2("[%d][EBP]", displacement); +            offset = M.x86.R_EBP + displacement; +            break; +          case 2: +            displacement = (s32)fetch_long_imm(); +            DECODE_PRINTF2("[%d][EBP]", displacement); +            offset = M.x86.R_EBP + displacement; +            break; +          default: +            HALT_SYS(); +        } +        DECODE_PRINTF("[EAX]"); +        offset = M.x86.R_EAX; +        break; +      case 6: +        DECODE_PRINTF("[ESI]"); +        offset = M.x86.R_ESI; +        break; +      case 7: +        DECODE_PRINTF("[EDI]"); +        offset = M.x86.R_EDI; +        break; +      default: +        HALT_SYS(); +    } +    offset += decode_sib_si(ss, index); +    return offset; + +} + +/**************************************************************************** +PARAMETERS: +rm  - RM value to decode + +RETURNS: +Offset in memory for the address decoding + +REMARKS: +Return the offset given by mod=00 addressing.  Also enables the +decoding of instructions. + +NOTE:   The code which specifies the corresponding segment (ds vs ss) +        below in the case of [BP+..].  The assumption here is that at the +        point that this subroutine is called, the bit corresponding to +        SYSMODE_SEG_DS_SS will be zero.  After every instruction +        except the segment override instructions, this bit (as well +        as any bits indicating segment overrides) will be clear.  So +        if a SS access is needed, set this bit.  Otherwise, DS access +        occurs (unless any of the segment override bits are set). +****************************************************************************/ +unsigned decode_rm00_address( +    int rm) +{ +    unsigned offset; + +    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { +        /* 32-bit addressing */ +        switch (rm) { +          case 0: +            DECODE_PRINTF("[EAX]"); +            return M.x86.R_EAX; +          case 1: +            DECODE_PRINTF("[ECX]"); +            return M.x86.R_ECX; +          case 2: +            DECODE_PRINTF("[EDX]"); +            return M.x86.R_EDX; +          case 3: +            DECODE_PRINTF("[EBX]"); +            return M.x86.R_EBX; +          case 4: +            return decode_sib_address(0); +          case 5: +            offset = fetch_long_imm(); +            DECODE_PRINTF2("[%08x]", offset); +            return offset; +          case 6: +            DECODE_PRINTF("[ESI]"); +            return M.x86.R_ESI; +          case 7: +            DECODE_PRINTF("[EDI]"); +            return M.x86.R_EDI; +        } +    } else { +        /* 16-bit addressing */ +        switch (rm) { +          case 0: +            DECODE_PRINTF("[BX+SI]"); +            return (M.x86.R_BX + M.x86.R_SI) & 0xffff; +          case 1: +            DECODE_PRINTF("[BX+DI]"); +            return (M.x86.R_BX + M.x86.R_DI) & 0xffff; +          case 2: +            DECODE_PRINTF("[BP+SI]"); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_SI) & 0xffff; +          case 3: +            DECODE_PRINTF("[BP+DI]"); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_DI) & 0xffff; +          case 4: +            DECODE_PRINTF("[SI]"); +            return M.x86.R_SI; +          case 5: +            DECODE_PRINTF("[DI]"); +            return M.x86.R_DI; +          case 6: +            offset = fetch_word_imm(); +            DECODE_PRINTF2("[%04x]", offset); +            return offset; +          case 7: +            DECODE_PRINTF("[BX]"); +            return M.x86.R_BX; +        } +    } +    HALT_SYS(); +    return 0; +} + +/**************************************************************************** +PARAMETERS: +rm  - RM value to decode + +RETURNS: +Offset in memory for the address decoding + +REMARKS: +Return the offset given by mod=01 addressing.  Also enables the +decoding of instructions. +****************************************************************************/ +unsigned decode_rm01_address( +    int rm) +{ +    int displacement; + +    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { +        /* 32-bit addressing */ +        if (rm != 4) +            displacement = (s8)fetch_byte_imm(); +        else +            displacement = 0; + +        switch (rm) { +          case 0: +            DECODE_PRINTF2("%d[EAX]", displacement); +            return M.x86.R_EAX + displacement; +          case 1: +            DECODE_PRINTF2("%d[ECX]", displacement); +            return M.x86.R_ECX + displacement; +          case 2: +            DECODE_PRINTF2("%d[EDX]", displacement); +            return M.x86.R_EDX + displacement; +          case 3: +            DECODE_PRINTF2("%d[EBX]", displacement); +            return M.x86.R_EBX + displacement; +          case 4: { +            int offset = decode_sib_address(1); +            displacement = (s8)fetch_byte_imm(); +            DECODE_PRINTF2("[%d]", displacement); +            return offset + displacement; +          } +          case 5: +            DECODE_PRINTF2("%d[EBP]", displacement); +            return M.x86.R_EBP + displacement; +          case 6: +            DECODE_PRINTF2("%d[ESI]", displacement); +            return M.x86.R_ESI + displacement; +          case 7: +            DECODE_PRINTF2("%d[EDI]", displacement); +            return M.x86.R_EDI + displacement; +        } +    } else { +        /* 16-bit addressing */ +        displacement = (s8)fetch_byte_imm(); +        switch (rm) { +          case 0: +            DECODE_PRINTF2("%d[BX+SI]", displacement); +            return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; +          case 1: +            DECODE_PRINTF2("%d[BX+DI]", displacement); +            return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; +          case 2: +            DECODE_PRINTF2("%d[BP+SI]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; +          case 3: +            DECODE_PRINTF2("%d[BP+DI]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; +          case 4: +            DECODE_PRINTF2("%d[SI]", displacement); +            return (M.x86.R_SI + displacement) & 0xffff; +          case 5: +            DECODE_PRINTF2("%d[DI]", displacement); +            return (M.x86.R_DI + displacement) & 0xffff; +          case 6: +            DECODE_PRINTF2("%d[BP]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + displacement) & 0xffff; +          case 7: +            DECODE_PRINTF2("%d[BX]", displacement); +            return (M.x86.R_BX + displacement) & 0xffff; +        } +    } +    HALT_SYS(); +    return 0;                   /* SHOULD NOT HAPPEN */ +} + +/**************************************************************************** +PARAMETERS: +rm  - RM value to decode + +RETURNS: +Offset in memory for the address decoding + +REMARKS: +Return the offset given by mod=10 addressing.  Also enables the +decoding of instructions. +****************************************************************************/ +unsigned decode_rm10_address( +    int rm) +{ +    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { +        int displacement; + +        /* 32-bit addressing */ +        if (rm != 4) +            displacement = (s32)fetch_long_imm(); +        else +            displacement = 0; + +        switch (rm) { +          case 0: +            DECODE_PRINTF2("%d[EAX]", displacement); +            return M.x86.R_EAX + displacement; +          case 1: +            DECODE_PRINTF2("%d[ECX]", displacement); +            return M.x86.R_ECX + displacement; +          case 2: +            DECODE_PRINTF2("%d[EDX]", displacement); +            return M.x86.R_EDX + displacement; +          case 3: +            DECODE_PRINTF2("%d[EBX]", displacement); +            return M.x86.R_EBX + displacement; +          case 4: { +            int offset = decode_sib_address(2); +            displacement = (s32)fetch_long_imm(); +            DECODE_PRINTF2("[%d]", displacement); +            return offset + displacement; +          } +          case 5: +            DECODE_PRINTF2("%d[EBP]", displacement); +            return M.x86.R_EBP + displacement; +          case 6: +            DECODE_PRINTF2("%d[ESI]", displacement); +            return M.x86.R_ESI + displacement; +          case 7: +            DECODE_PRINTF2("%d[EDI]", displacement); +            return M.x86.R_EDI + displacement; +        } +    } else { +        int displacement = (s16)fetch_word_imm(); + +        /* 16-bit addressing */ +        switch (rm) { +          case 0: +            DECODE_PRINTF2("%d[BX+SI]", displacement); +            return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; +          case 1: +            DECODE_PRINTF2("%d[BX+DI]", displacement); +            return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; +          case 2: +            DECODE_PRINTF2("%d[BP+SI]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; +          case 3: +            DECODE_PRINTF2("%d[BP+DI]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; +          case 4: +            DECODE_PRINTF2("%d[SI]", displacement); +            return (M.x86.R_SI + displacement) & 0xffff; +          case 5: +            DECODE_PRINTF2("%d[DI]", displacement); +            return (M.x86.R_DI + displacement) & 0xffff; +          case 6: +            DECODE_PRINTF2("%d[BP]", displacement); +            M.x86.mode |= SYSMODE_SEG_DS_SS; +            return (M.x86.R_BP + displacement) & 0xffff; +          case 7: +            DECODE_PRINTF2("%d[BX]", displacement); +            return (M.x86.R_BX + displacement) & 0xffff; +        } +    } +    HALT_SYS(); +    return 0;                   /* SHOULD NOT HAPPEN */ +} + + +/**************************************************************************** +PARAMETERS: +mod - modifier +rm  - RM value to decode + +RETURNS: +Offset in memory for the address decoding, multiplexing calls to +the decode_rmXX_address functions + +REMARKS: +Return the offset given by "mod" addressing. +****************************************************************************/ + +unsigned decode_rmXX_address(int mod, int rm) +{ +  if(mod == 0) +    return decode_rm00_address(rm); +  if(mod == 1) +    return decode_rm01_address(rm); +  return decode_rm10_address(rm); +} + + + diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c new file mode 100644 index 000000000..632979dd5 --- /dev/null +++ b/drivers/bios_emulator/x86emu/ops.c @@ -0,0 +1,5431 @@ +/**************************************************************************** +*			Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*            	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 preceeding 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 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. +* +* Jason ported this file to u-boot. place all the function pointer in +* the got2 sector. Removed some opcode. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" +/*----------------------------- Implementation ----------------------------*/ + +/* constant arrays to do several instructions in just one function */ + +#ifdef DEBUG +static 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) __attribute__ ((section(".got2"))) = +{ +    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) __attribute__ ((section(".got2"))) = +{ +    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) __attribute__ ((section(".got2"))) = +{ +    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) __attribute__ ((section(".got2"))) = +{ +    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) __attribute__ ((section(".got2"))) = +{ +    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) __attribute__ ((section(".got2"))) = +{ +    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 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. +****************************************************************************/ +void x86emuOp_illegal_op( +    u8 op1) +{ +    START_OF_INSTR(); +    if (M.x86.R_SP != 0) { +        DECODE_PRINTF("ILLEGAL X86 OPCODE\n"); +        TRACE_REGS(); +        DB( printk("%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 +****************************************************************************/ +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); +        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 +****************************************************************************/ +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); +            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); +            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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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) +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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(); +    push_word(imm); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6b +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +int x86emu_check_jump_condition(u8 op); + +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; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x80 +****************************************************************************/ +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(); +        destval = (*genop_byte_operation[rh]) (*destreg, imm); +        if (rh != 7) +            *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x81 +****************************************************************************/ +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; +            u32 destval,imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            imm = fetch_long_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } else { +            u16 *destreg; +            u16 destval,imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            imm = fetch_word_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x82 +****************************************************************************/ +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(); +        destval = (*genop_byte_operation[rh]) (*destreg, imm); +        if (rh != 7) +            *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x83 +****************************************************************************/ +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; +            u32 destval,imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } else { +            u16 *destreg; +            u16 destval,imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x84 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u16 *srcreg; +    uint destoffset; + +/* + * TODO: Need to handle address size prefix! + * + * lea  eax,[eax+ebx*2] ?? + */ + +    START_OF_INSTR(); +    DECODE_PRINTF("LEA\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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_EAX = *reg16; +        *reg16 = (u16)tmp; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x98 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 farseg, faroff; + +    START_OF_INSTR(); +	DECODE_PRINTF("CALL\t"); +	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; +    push_word(M.x86.R_IP); +    M.x86.R_IP = faroff; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9b +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 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; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa5 +****************************************************************************/ +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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 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; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa6 +****************************************************************************/ +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 CX is ZERO. */ +        while (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); +            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; +        } +        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 +****************************************************************************/ +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 CX is ZERO. */ +        while (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); +            } +            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; +        } +        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 +****************************************************************************/ +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 +****************************************************************************/ +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 +****************************************************************************/ +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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +        } +        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 +****************************************************************************/ +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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 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; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xac +****************************************************************************/ +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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +            M.x86.R_CX -= 1; +            M.x86.R_SI += inc; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +        M.x86.R_SI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xad +****************************************************************************/ +void x86emuOp_lods_word(u8 X86EMU_UNUSED(op1)) +{ +    int inc; +    u32 count; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("LODS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("LODS\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)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 0; +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } +    while (count--) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_EAX = fetch_data_long(M.x86.R_SI); +        } else { +            M.x86.R_AX = fetch_data_word(M.x86.R_SI); +        } +        M.x86.R_SI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xae +****************************************************************************/ +void x86emuOp_scas_byte(u8 X86EMU_UNUSED(op1)) +{ +    s8 val2; +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("SCAS\tBYTE\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; +    if (M.x86.mode & SYSMODE_PREFIX_REPE) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_byte(M.x86.R_AL, val2); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF) == 0) +                break; +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPE; +    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { +        /* REPNE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_byte(M.x86.R_AL, val2); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF)) +                break;          /* zero flag set means equal */ +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPNE; +    } else { +        val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +        cmp_byte(M.x86.R_AL, val2); +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaf +****************************************************************************/ +void x86emuOp_scas_word(u8 X86EMU_UNUSED(op1)) +{ +    int inc; +    u32 val; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("SCAS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("SCAS\tWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -2; +        else +            inc = 2; +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_REPE) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_long(M.x86.R_EAX, val); +            } else { +                val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_word(M.x86.R_AX, (u16)val); +            } +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF) == 0) +                break; +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPE; +    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { +        /* REPNE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_long(M.x86.R_EAX, val); +            } else { +                val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_word(M.x86.R_AX, (u16)val); +            } +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF)) +                break;          /* zero flag set means equal */ +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPNE; +    } else { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_long(M.x86.R_EAX, val); +        } else { +            val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_word(M.x86.R_AX, (u16)val); +        } +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb0 - 0xb7 +****************************************************************************/ +void x86emuOp_mov_byte_register_IMM(u8 op1) +{ +    u8 imm, *ptr; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    ptr = DECODE_RM_BYTE_REGISTER(op1 & 0x7); +    DECODE_PRINTF(","); +    imm = fetch_byte_imm(); +    DECODE_PRINTF2("%x\n", imm); +    TRACE_AND_STEP(); +    *ptr = imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb8 - 0xbf +****************************************************************************/ +void x86emuOp_mov_word_register_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u32 srcval; + +    op1 &= 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg32; +        reg32 = DECODE_RM_LONG_REGISTER(op1); +        srcval = fetch_long_imm(); +        DECODE_PRINTF2(",%x\n", srcval); +        TRACE_AND_STEP(); +        *reg32 = srcval; +    } else { +        u16 *reg16; +        reg16 = DECODE_RM_WORD_REGISTER(op1); +        srcval = fetch_word_imm(); +        DECODE_PRINTF2(",%x\n", srcval); +        TRACE_AND_STEP(); +        *reg16 = (u16)srcval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc0 +****************************************************************************/ +void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; +    u8 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\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); +        amt = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", amt); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, amt); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        amt = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", amt); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, amt); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc1 +****************************************************************************/ +void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, amt); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, amt); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); +        } else { +            u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc2 +****************************************************************************/ +void x86emuOp_ret_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("RET\t"); +    imm = fetch_word_imm(); +    DECODE_PRINTF2("%x\n", imm); +	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_SP += imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc3 +****************************************************************************/ +void x86emuOp_ret_near(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("RET\n"); +	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc4 +****************************************************************************/ +void x86emuOp_les_R_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LES\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_ES = fetch_data_word(srcoffset + 2); +    } +    /* else UNDEFINED!                   register to register */ + +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc5 +****************************************************************************/ +void x86emuOp_lds_R_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LDS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_DS = fetch_data_word(srcoffset + 2); +    } +    /* else UNDEFINED! */ +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc6 +****************************************************************************/ +void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (rh != 0) { +        DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n"); +        HALT_SYS(); +    } +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%2x\n", imm); +        TRACE_AND_STEP(); +        store_data_byte(destoffset, imm); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%2x\n", imm); +        TRACE_AND_STEP(); +        *destreg = imm; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc7 +****************************************************************************/ +void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (rh != 0) { +        DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); +        HALT_SYS(); +    } +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 imm; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            store_data_long(destoffset, imm); +        } else { +            u16 imm; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            store_data_word(destoffset, imm); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +			u32 *destreg; +			u32 imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            *destreg = imm; +        } else { +			u16 *destreg; +			u16 imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            *destreg = imm; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc8 +****************************************************************************/ +void x86emuOp_enter(u8 X86EMU_UNUSED(op1)) +{ +    u16 local,frame_pointer; +    u8  nesting; +    int i; + +    START_OF_INSTR(); +    local = fetch_word_imm(); +    nesting = fetch_byte_imm(); +    DECODE_PRINTF2("ENTER %x\n", local); +    DECODE_PRINTF2(",%x\n", nesting); +    TRACE_AND_STEP(); +    push_word(M.x86.R_BP); +    frame_pointer = M.x86.R_SP; +    if (nesting > 0) { +        for (i = 1; i < nesting; i++) { +            M.x86.R_BP -= 2; +            push_word(fetch_data_word_abs(M.x86.R_SS, M.x86.R_BP)); +            } +        push_word(frame_pointer); +        } +    M.x86.R_BP = frame_pointer; +    M.x86.R_SP = (u16)(M.x86.R_SP - local); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc9 +****************************************************************************/ +void x86emuOp_leave(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("LEAVE\n"); +    TRACE_AND_STEP(); +    M.x86.R_SP = M.x86.R_BP; +    M.x86.R_BP = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xca +****************************************************************************/ +void x86emuOp_ret_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("RETF\t"); +    imm = fetch_word_imm(); +    DECODE_PRINTF2("%x\n", imm); +	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    M.x86.R_SP += imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcb +****************************************************************************/ +void x86emuOp_ret_far(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("RETF\n"); +	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcc +****************************************************************************/ +void x86emuOp_int3(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; + +    START_OF_INSTR(); +    DECODE_PRINTF("INT 3\n"); +    tmp = (u16) mem_access_word(3 * 4 + 2); +    /* access the segment register */ +    TRACE_AND_STEP(); +	if (_X86EMU_intrTab[3]) { +		(*_X86EMU_intrTab[3])(3); +    } else { +        push_word((u16)M.x86.R_FLG); +        CLEAR_FLAG(F_IF); +        CLEAR_FLAG(F_TF); +        push_word(M.x86.R_CS); +        M.x86.R_CS = mem_access_word(3 * 4 + 2); +        push_word(M.x86.R_IP); +        M.x86.R_IP = mem_access_word(3 * 4); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcd +****************************************************************************/ +void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; +    u8 intnum; + +    START_OF_INSTR(); +    DECODE_PRINTF("INT\t"); +    intnum = fetch_byte_imm(); +    DECODE_PRINTF2("%x\n", intnum); +    tmp = mem_access_word(intnum * 4 + 2); +    TRACE_AND_STEP(); +	if (_X86EMU_intrTab[intnum]) { +		(*_X86EMU_intrTab[intnum])(intnum); +    } else { +        push_word((u16)M.x86.R_FLG); +        CLEAR_FLAG(F_IF); +        CLEAR_FLAG(F_TF); +        push_word(M.x86.R_CS); +        M.x86.R_CS = mem_access_word(intnum * 4 + 2); +        push_word(M.x86.R_IP); +        M.x86.R_IP = mem_access_word(intnum * 4); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xce +****************************************************************************/ +void x86emuOp_into(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; + +    START_OF_INSTR(); +    DECODE_PRINTF("INTO\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_OF)) { +        tmp = mem_access_word(4 * 4 + 2); +		if (_X86EMU_intrTab[4]) { +			(*_X86EMU_intrTab[4])(4); +        } else { +            push_word((u16)M.x86.R_FLG); +            CLEAR_FLAG(F_IF); +            CLEAR_FLAG(F_TF); +            push_word(M.x86.R_CS); +            M.x86.R_CS = mem_access_word(4 * 4 + 2); +            push_word(M.x86.R_IP); +            M.x86.R_IP = mem_access_word(4 * 4); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcf +****************************************************************************/ +void x86emuOp_iret(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("IRET\n"); + +    TRACE_AND_STEP(); + +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    M.x86.R_FLG = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd0 +****************************************************************************/ +void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; + +    /* +     * 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\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(",1\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, 1); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(",1\n"); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, 1); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd1 +****************************************************************************/ +void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    /* +     * 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",1\n"); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, 1); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",1\n"); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, 1); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +			u32 destval; +			u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(",1\n"); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (*destreg, 1); +            *destreg = destval; +        } else { +			u16 destval; +			u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(",1\n"); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (*destreg, 1); +            *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd2 +****************************************************************************/ +void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; +    u8 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    amt = M.x86.R_CL; +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(",CL\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, amt); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(",CL\n"); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, amt); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd3 +****************************************************************************/ +void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 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 +     */ +    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("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    amt = M.x86.R_CL; +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",CL\n"); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, amt); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",CL\n"); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, amt); +            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(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); +        } else { +            u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd4 +****************************************************************************/ +void x86emuOp_aam(u8 X86EMU_UNUSED(op1)) +{ +    u8 a; + +    START_OF_INSTR(); +    DECODE_PRINTF("AAM\n"); +    a = fetch_byte_imm();      /* this is a stupid encoding. */ +    if (a != 10) { +        DECODE_PRINTF("ERROR DECODING AAM\n"); +        TRACE_REGS(); +        HALT_SYS(); +    } +    TRACE_AND_STEP(); +    /* note the type change here --- returning AL and AH in AX. */ +    M.x86.R_AX = aam_word(M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd5 +****************************************************************************/ +void x86emuOp_aad(u8 X86EMU_UNUSED(op1)) +{ +    u8 a; + +    START_OF_INSTR(); +    DECODE_PRINTF("AAD\n"); +    a = fetch_byte_imm(); +    TRACE_AND_STEP(); +    M.x86.R_AX = aad_word(M.x86.R_AX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/* opcode 0xd6 ILLEGAL OPCODE */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xd7 +****************************************************************************/ +void x86emuOp_xlat(u8 X86EMU_UNUSED(op1)) +{ +    u16 addr; + +    START_OF_INSTR(); +    DECODE_PRINTF("XLAT\n"); +    TRACE_AND_STEP(); +	addr = (u16)(M.x86.R_BX + (u8)M.x86.R_AL); +    M.x86.R_AL = fetch_data_byte(addr); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/* instuctions  D8 .. DF are in i87_ops.c */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xe0 +****************************************************************************/ +void x86emuOp_loopne(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOPNE\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF))      /* CX != 0 and !ZF */ +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe1 +****************************************************************************/ +void x86emuOp_loope(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOPE\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF))       /* CX != 0 and ZF */ +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe2 +****************************************************************************/ +void x86emuOp_loop(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOP\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0) +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe3 +****************************************************************************/ +void x86emuOp_jcxz(u8 X86EMU_UNUSED(op1)) +{ +    u16 target; +    s8  offset; + +    /* jump to byte offset if overflow flag is set */ +    START_OF_INSTR(); +    DECODE_PRINTF("JCXZ\t"); +    offset = (s8)fetch_byte_imm(); +    target = (u16)(M.x86.R_IP + offset); +    DECODE_PRINTF2("%x\n", target); +    TRACE_AND_STEP(); +    if (M.x86.R_CX == 0) +        M.x86.R_IP = target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe4 +****************************************************************************/ +void x86emuOp_in_byte_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("IN\t"); +	port = (u8) fetch_byte_imm(); +    DECODE_PRINTF2("%x,AL\n", port); +    TRACE_AND_STEP(); +    M.x86.R_AL = (*sys_inb)(port); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe5 +****************************************************************************/ +void x86emuOp_in_word_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("IN\t"); +	port = (u8) fetch_byte_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("EAX,%x\n", port); +    } else { +        DECODE_PRINTF2("AX,%x\n", port); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = (*sys_inl)(port); +    } else { +        M.x86.R_AX = (*sys_inw)(port); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe6 +****************************************************************************/ +void x86emuOp_out_byte_IMM_AL(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\t"); +	port = (u8) fetch_byte_imm(); +    DECODE_PRINTF2("%x,AL\n", port); +    TRACE_AND_STEP(); +    (*sys_outb)(port, M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe7 +****************************************************************************/ +void x86emuOp_out_word_IMM_AX(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\t"); +	port = (u8) fetch_byte_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("%x,EAX\n", port); +    } else { +        DECODE_PRINTF2("%x,AX\n", port); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        (*sys_outl)(port, M.x86.R_EAX); +    } else { +        (*sys_outw)(port, M.x86.R_AX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe8 +****************************************************************************/ +void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +	DECODE_PRINTF("CALL\t"); +	ip = (s16) fetch_word_imm(); +	ip += (s16) M.x86.R_IP;    /* CHECK SIGN */ +	DECODE_PRINTF2("%04x\n", ip); +	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, ""); +    TRACE_AND_STEP(); +    push_word(M.x86.R_IP); +    M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe9 +****************************************************************************/ +void x86emuOp_jump_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\t"); +    ip = (s16)fetch_word_imm(); +    ip += (s16)M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_IP = (u16)ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xea +****************************************************************************/ +void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 cs, ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\tFAR "); +    ip = fetch_word_imm(); +    cs = fetch_word_imm(); +    DECODE_PRINTF2("%04x:", cs); +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_IP = ip; +    M.x86.R_CS = cs; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xeb +****************************************************************************/ +void x86emuOp_jump_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 target; +    s8 offset; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\t"); +    offset = (s8)fetch_byte_imm(); +    target = (u16)(M.x86.R_IP + offset); +    DECODE_PRINTF2("%x\n", target); +    TRACE_AND_STEP(); +    M.x86.R_IP = target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xec +****************************************************************************/ +void x86emuOp_in_byte_AL_DX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("IN\tAL,DX\n"); +    TRACE_AND_STEP(); +    M.x86.R_AL = (*sys_inb)(M.x86.R_DX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xed +****************************************************************************/ +void x86emuOp_in_word_AX_DX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("IN\tEAX,DX\n"); +    } else { +        DECODE_PRINTF("IN\tAX,DX\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = (*sys_inl)(M.x86.R_DX); +    } else { +        M.x86.R_AX = (*sys_inw)(M.x86.R_DX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xee +****************************************************************************/ +void x86emuOp_out_byte_DX_AL(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\tDX,AL\n"); +    TRACE_AND_STEP(); +    (*sys_outb)(M.x86.R_DX, M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xef +****************************************************************************/ +void x86emuOp_out_word_DX_AX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("OUT\tDX,EAX\n"); +    } else { +        DECODE_PRINTF("OUT\tDX,AX\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        (*sys_outl)(M.x86.R_DX, M.x86.R_EAX); +    } else { +        (*sys_outw)(M.x86.R_DX, M.x86.R_AX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf0 +****************************************************************************/ +void x86emuOp_lock(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("LOCK:\n"); +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*opcode 0xf1 ILLEGAL OPERATION */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xf2 +****************************************************************************/ +void x86emuOp_repne(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("REPNE\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_REPNE; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf3 +****************************************************************************/ +void x86emuOp_repe(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("REPE\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_REPE; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf4 +****************************************************************************/ +void x86emuOp_halt(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("HALT\n"); +    TRACE_AND_STEP(); +    HALT_SYS(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf5 +****************************************************************************/ +void x86emuOp_cmc(u8 X86EMU_UNUSED(op1)) +{ +    /* complement the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CMC\n"); +    TRACE_AND_STEP(); +    TOGGLE_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf6 +****************************************************************************/ +void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval, srcval; + +    /* long, drawn out code follows.  Double switch for a total +       of 32 cases.  */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    DECODE_PRINTF(opF6_names[rh]); +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        destval = fetch_data_byte(destoffset); + +        switch (rh) { +        case 0:         /* test byte imm */ +            DECODE_PRINTF(","); +            srcval = fetch_byte_imm(); +            DECODE_PRINTF2("%02x\n", srcval); +            TRACE_AND_STEP(); +            test_byte(destval, srcval); +            break; +        case 1: +            DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +            HALT_SYS(); +            break; +        case 2: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = not_byte(destval); +            store_data_byte(destoffset, destval); +            break; +        case 3: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = neg_byte(destval); +            store_data_byte(destoffset, destval); +            break; +        case 4: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            mul_byte(destval); +            break; +        case 5: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            imul_byte(destval); +            break; +        case 6: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            div_byte(destval); +            break; +        default: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            idiv_byte(destval); +            break; +        } +    } else {                     /* mod=11 */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        switch (rh) { +        case 0:         /* test byte imm */ +            DECODE_PRINTF(","); +            srcval = fetch_byte_imm(); +            DECODE_PRINTF2("%02x\n", srcval); +            TRACE_AND_STEP(); +            test_byte(*destreg, srcval); +            break; +        case 1: +            DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +            HALT_SYS(); +            break; +        case 2: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = not_byte(*destreg); +            break; +        case 3: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = neg_byte(*destreg); +            break; +        case 4: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            mul_byte(*destreg);      /*!!!  */ +            break; +        case 5: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            imul_byte(*destreg); +            break; +        case 6: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            div_byte(*destreg); +            break; +        default: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            idiv_byte(*destreg); +            break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf7 +****************************************************************************/ +void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    DECODE_PRINTF(opF6_names[rh]); +    if (mod < 3) { + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval, srcval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            destval = fetch_data_long(destoffset); + +            switch (rh) { +            case 0: +                DECODE_PRINTF(","); +                srcval = fetch_long_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_long(destval, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = not_long(destval); +                store_data_long(destoffset, destval); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = neg_long(destval); +                store_data_long(destoffset, destval); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_long(destval); +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_long(destval); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_long(destval); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_long(destval); +                break; +            } +        } else { +            u16 destval, srcval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            destval = fetch_data_word(destoffset); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_word_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_word(destval, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = not_word(destval); +                store_data_word(destoffset, destval); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = neg_word(destval); +                store_data_word(destoffset, destval); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_word(destval); +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_word(destval); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_word(destval); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_word(destval); +                break; +            } +        } + +    } else {                     /* mod=11 */ + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; + +            destreg = DECODE_RM_LONG_REGISTER(rl); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_long_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_long(*destreg, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = not_long(*destreg); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = neg_long(*destreg); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_long(*destreg);      /*!!!  */ +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_long(*destreg); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_long(*destreg); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_long(*destreg); +                break; +            } +        } else { +            u16 *destreg; +            u16 srcval; + +            destreg = DECODE_RM_WORD_REGISTER(rl); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_word_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_word(*destreg, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = not_word(*destreg); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = neg_word(*destreg); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_word(*destreg);      /*!!!  */ +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_word(*destreg); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_word(*destreg); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_word(*destreg); +                break; +            } +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf8 +****************************************************************************/ +void x86emuOp_clc(u8 X86EMU_UNUSED(op1)) +{ +    /* clear the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLC\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf9 +****************************************************************************/ +void x86emuOp_stc(u8 X86EMU_UNUSED(op1)) +{ +    /* set the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STC\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfa +****************************************************************************/ +void x86emuOp_cli(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLI\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_IF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfb +****************************************************************************/ +void x86emuOp_sti(u8 X86EMU_UNUSED(op1)) +{ +    /* enable  interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STI\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_IF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfc +****************************************************************************/ +void x86emuOp_cld(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLD\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_DF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfd +****************************************************************************/ +void x86emuOp_std(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STD\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_DF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfe +****************************************************************************/ +void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u8 destval; +    uint destoffset; +    u8 *destreg; + +    /* Yet another special case 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("INC\t"); +            break; +        case 1: +            DECODE_PRINTF("DEC\t"); +            break; +        case 2: +        case 3: +        case 4: +        case 5: +        case 6: +        case 7: +            DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod); +            HALT_SYS(); +            break; +        } +    } +#endif +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        if (rh == 0) +          destval = inc_byte(destval); +        else +          destval = dec_byte(destval); +        store_data_byte(destoffset, destval); +    } else { +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        if (rh == 0) +          *destreg = inc_byte(*destreg); +        else +          *destreg = dec_byte(*destreg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xff +****************************************************************************/ +void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    uint destoffset = 0; +	u16 *destreg; +	u16 destval,destval2; + +    /* Yet another special case 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: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                DECODE_PRINTF("INC\tDWORD PTR "); +            } else { +                DECODE_PRINTF("INC\tWORD PTR "); +            } +            break; +        case 1: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                DECODE_PRINTF("DEC\tDWORD PTR "); +            } else { +                DECODE_PRINTF("DEC\tWORD PTR "); +            } +            break; +        case 2: +            DECODE_PRINTF("CALL\t "); +            break; +        case 3: +            DECODE_PRINTF("CALL\tFAR "); +            break; +        case 4: +            DECODE_PRINTF("JMP\t"); +            break; +        case 5: +            DECODE_PRINTF("JMP\tFAR "); +            break; +        case 6: +            DECODE_PRINTF("PUSH\t"); +            break; +        case 7: +            DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t"); +            HALT_SYS(); +            break; +        } +    } +#endif +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        switch (rh) { +        case 0:         /* inc word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                destval = inc_long(destval); +                store_data_long(destoffset, destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                destval = inc_word(destval); +                store_data_word(destoffset, destval); +            } +            break; +        case 1:         /* dec word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                destval = dec_long(destval); +                store_data_long(destoffset, destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                destval = dec_word(destval); +                store_data_word(destoffset, destval); +            } +            break; +        case 2:         /* call word ptr ... */ +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            push_word(M.x86.R_IP); +            M.x86.R_IP = destval; +            break; +        case 3:         /* call far ptr ... */ +            destval = fetch_data_word(destoffset); +            destval2 = fetch_data_word(destoffset + 2); +            TRACE_AND_STEP(); +            push_word(M.x86.R_CS); +            M.x86.R_CS = destval2; +            push_word(M.x86.R_IP); +            M.x86.R_IP = destval; +            break; +        case 4:         /* jmp word ptr ... */ +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            M.x86.R_IP = destval; +            break; +        case 5:         /* jmp far ptr ... */ +            destval = fetch_data_word(destoffset); +            destval2 = fetch_data_word(destoffset + 2); +            TRACE_AND_STEP(); +            M.x86.R_IP = destval; +            M.x86.R_CS = destval2; +            break; +        case 6:         /*  push word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                push_long(destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                push_word(destval); +            } +            break; +        } +    } else { +        switch (rh) { +        case 0: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = inc_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = inc_word(*destreg); +            } +            break; +        case 1: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = dec_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = dec_word(*destreg); +            } +            break; +        case 2:         /* call word ptr ... */ +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            push_word(M.x86.R_IP); +            M.x86.R_IP = *destreg; +            break; +        case 3:         /* jmp far ptr ... */ +            DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); +            TRACE_AND_STEP(); +            HALT_SYS(); +            break; + +        case 4:         /* jmp  ... */ +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            M.x86.R_IP = (u16) (*destreg); +            break; +        case 5:         /* jmp far ptr ... */ +            DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); +            TRACE_AND_STEP(); +            HALT_SYS(); +            break; +        case 6: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                push_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                push_word(*destreg); +            } +            break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*************************************************************************** + * Single byte operation code table: + **************************************************************************/ +void (*x86emu_optab[256])(u8) __attribute__ ((section(".got2"))) = +{ +/*  0x00 */ x86emuOp_genop_byte_RM_R, +/*  0x01 */ x86emuOp_genop_word_RM_R, +/*  0x02 */ x86emuOp_genop_byte_R_RM, +/*  0x03 */ x86emuOp_genop_word_R_RM, +/*  0x04 */ x86emuOp_genop_byte_AL_IMM, +/*  0x05 */ x86emuOp_genop_word_AX_IMM, +/*  0x06 */ x86emuOp_push_ES, +/*  0x07 */ x86emuOp_pop_ES, + +/*  0x08 */ x86emuOp_genop_byte_RM_R, +/*  0x09 */ x86emuOp_genop_word_RM_R, +/*  0x0a */ x86emuOp_genop_byte_R_RM, +/*  0x0b */ x86emuOp_genop_word_R_RM, +/*  0x0c */ x86emuOp_genop_byte_AL_IMM, +/*  0x0d */ x86emuOp_genop_word_AX_IMM, +/*  0x0e */ x86emuOp_push_CS, +/*  0x0f */ x86emuOp_two_byte, + +/*  0x10 */ x86emuOp_genop_byte_RM_R, +/*  0x11 */ x86emuOp_genop_word_RM_R, +/*  0x12 */ x86emuOp_genop_byte_R_RM, +/*  0x13 */ x86emuOp_genop_word_R_RM, +/*  0x14 */ x86emuOp_genop_byte_AL_IMM, +/*  0x15 */ x86emuOp_genop_word_AX_IMM, +/*  0x16 */ x86emuOp_push_SS, +/*  0x17 */ x86emuOp_pop_SS, + +/*  0x18 */ x86emuOp_genop_byte_RM_R, +/*  0x19 */ x86emuOp_genop_word_RM_R, +/*  0x1a */ x86emuOp_genop_byte_R_RM, +/*  0x1b */ x86emuOp_genop_word_R_RM, +/*  0x1c */ x86emuOp_genop_byte_AL_IMM, +/*  0x1d */ x86emuOp_genop_word_AX_IMM, +/*  0x1e */ x86emuOp_push_DS, +/*  0x1f */ x86emuOp_pop_DS, + +/*  0x20 */ x86emuOp_genop_byte_RM_R, +/*  0x21 */ x86emuOp_genop_word_RM_R, +/*  0x22 */ x86emuOp_genop_byte_R_RM, +/*  0x23 */ x86emuOp_genop_word_R_RM, +/*  0x24 */ x86emuOp_genop_byte_AL_IMM, +/*  0x25 */ x86emuOp_genop_word_AX_IMM, +/*  0x26 */ x86emuOp_segovr_ES, +/*  0x27 */ x86emuOp_daa, + +/*  0x28 */ x86emuOp_genop_byte_RM_R, +/*  0x29 */ x86emuOp_genop_word_RM_R, +/*  0x2a */ x86emuOp_genop_byte_R_RM, +/*  0x2b */ x86emuOp_genop_word_R_RM, +/*  0x2c */ x86emuOp_genop_byte_AL_IMM, +/*  0x2d */ x86emuOp_genop_word_AX_IMM, +/*  0x2e */ x86emuOp_segovr_CS, +/*  0x2f */ x86emuOp_das, + +/*  0x30 */ x86emuOp_genop_byte_RM_R, +/*  0x31 */ x86emuOp_genop_word_RM_R, +/*  0x32 */ x86emuOp_genop_byte_R_RM, +/*  0x33 */ x86emuOp_genop_word_R_RM, +/*  0x34 */ x86emuOp_genop_byte_AL_IMM, +/*  0x35 */ x86emuOp_genop_word_AX_IMM, +/*  0x36 */ x86emuOp_segovr_SS, +/*  0x37 */ x86emuOp_aaa, + +/*  0x38 */ x86emuOp_genop_byte_RM_R, +/*  0x39 */ x86emuOp_genop_word_RM_R, +/*  0x3a */ x86emuOp_genop_byte_R_RM, +/*  0x3b */ x86emuOp_genop_word_R_RM, +/*  0x3c */ x86emuOp_genop_byte_AL_IMM, +/*  0x3d */ x86emuOp_genop_word_AX_IMM, +/*  0x3e */ x86emuOp_segovr_DS, +/*  0x3f */ x86emuOp_aas, + +/*  0x40 */ x86emuOp_inc_register, +/*  0x41 */ x86emuOp_inc_register, +/*  0x42 */ x86emuOp_inc_register, +/*  0x43 */ x86emuOp_inc_register, +/*  0x44 */ x86emuOp_inc_register, +/*  0x45 */ x86emuOp_inc_register, +/*  0x46 */ x86emuOp_inc_register, +/*  0x47 */ x86emuOp_inc_register, + +/*  0x48 */ x86emuOp_dec_register, +/*  0x49 */ x86emuOp_dec_register, +/*  0x4a */ x86emuOp_dec_register, +/*  0x4b */ x86emuOp_dec_register, +/*  0x4c */ x86emuOp_dec_register, +/*  0x4d */ x86emuOp_dec_register, +/*  0x4e */ x86emuOp_dec_register, +/*  0x4f */ x86emuOp_dec_register, + +/*  0x50 */ x86emuOp_push_register, +/*  0x51 */ x86emuOp_push_register, +/*  0x52 */ x86emuOp_push_register, +/*  0x53 */ x86emuOp_push_register, +/*  0x54 */ x86emuOp_push_register, +/*  0x55 */ x86emuOp_push_register, +/*  0x56 */ x86emuOp_push_register, +/*  0x57 */ x86emuOp_push_register, + +/*  0x58 */ x86emuOp_pop_register, +/*  0x59 */ x86emuOp_pop_register, +/*  0x5a */ x86emuOp_pop_register, +/*  0x5b */ x86emuOp_pop_register, +/*  0x5c */ x86emuOp_pop_register, +/*  0x5d */ x86emuOp_pop_register, +/*  0x5e */ x86emuOp_pop_register, +/*  0x5f */ x86emuOp_pop_register, + +/*  0x60 */ x86emuOp_push_all, +/*  0x61 */ x86emuOp_pop_all, +/*  0x62 */ x86emuOp_illegal_op,   /* bound */ +/*  0x63 */ x86emuOp_illegal_op,   /* arpl */ +/*  0x64 */ x86emuOp_segovr_FS, +/*  0x65 */ x86emuOp_segovr_GS, +/*  0x66 */ x86emuOp_prefix_data, +/*  0x67 */ x86emuOp_prefix_addr, + +/*  0x68 */ x86emuOp_push_word_IMM, +/*  0x69 */ x86emuOp_imul_word_IMM, +/*  0x6a */ x86emuOp_push_byte_IMM, +/*  0x6b */ x86emuOp_imul_byte_IMM, +/*  0x6c */ x86emuOp_ins_byte, +/*  0x6d */ x86emuOp_ins_word, +/*  0x6e */ x86emuOp_outs_byte, +/*  0x6f */ x86emuOp_outs_word, + +/*  0x70 */ x86emuOp_jump_near_cond, +/*  0x71 */ x86emuOp_jump_near_cond, +/*  0x72 */ x86emuOp_jump_near_cond, +/*  0x73 */ x86emuOp_jump_near_cond, +/*  0x74 */ x86emuOp_jump_near_cond, +/*  0x75 */ x86emuOp_jump_near_cond, +/*  0x76 */ x86emuOp_jump_near_cond, +/*  0x77 */ x86emuOp_jump_near_cond, + +/*  0x78 */ x86emuOp_jump_near_cond, +/*  0x79 */ x86emuOp_jump_near_cond, +/*  0x7a */ x86emuOp_jump_near_cond, +/*  0x7b */ x86emuOp_jump_near_cond, +/*  0x7c */ x86emuOp_jump_near_cond, +/*  0x7d */ x86emuOp_jump_near_cond, +/*  0x7e */ x86emuOp_jump_near_cond, +/*  0x7f */ x86emuOp_jump_near_cond, + +/*  0x80 */ x86emuOp_opc80_byte_RM_IMM, +/*  0x81 */ x86emuOp_opc81_word_RM_IMM, +/*  0x82 */ x86emuOp_opc82_byte_RM_IMM, +/*  0x83 */ x86emuOp_opc83_word_RM_IMM, +/*  0x84 */ x86emuOp_test_byte_RM_R, +/*  0x85 */ x86emuOp_test_word_RM_R, +/*  0x86 */ x86emuOp_xchg_byte_RM_R, +/*  0x87 */ x86emuOp_xchg_word_RM_R, + +/*  0x88 */ x86emuOp_mov_byte_RM_R, +/*  0x89 */ x86emuOp_mov_word_RM_R, +/*  0x8a */ x86emuOp_mov_byte_R_RM, +/*  0x8b */ x86emuOp_mov_word_R_RM, +/*  0x8c */ x86emuOp_mov_word_RM_SR, +/*  0x8d */ x86emuOp_lea_word_R_M, +/*  0x8e */ x86emuOp_mov_word_SR_RM, +/*  0x8f */ x86emuOp_pop_RM, + +/*  0x90 */ x86emuOp_nop, +/*  0x91 */ x86emuOp_xchg_word_AX_register, +/*  0x92 */ x86emuOp_xchg_word_AX_register, +/*  0x93 */ x86emuOp_xchg_word_AX_register, +/*  0x94 */ x86emuOp_xchg_word_AX_register, +/*  0x95 */ x86emuOp_xchg_word_AX_register, +/*  0x96 */ x86emuOp_xchg_word_AX_register, +/*  0x97 */ x86emuOp_xchg_word_AX_register, + +/*  0x98 */ x86emuOp_cbw, +/*  0x99 */ x86emuOp_cwd, +/*  0x9a */ x86emuOp_call_far_IMM, +/*  0x9b */ x86emuOp_wait, +/*  0x9c */ x86emuOp_pushf_word, +/*  0x9d */ x86emuOp_popf_word, +/*  0x9e */ x86emuOp_sahf, +/*  0x9f */ x86emuOp_lahf, + +/*  0xa0 */ x86emuOp_mov_AL_M_IMM, +/*  0xa1 */ x86emuOp_mov_AX_M_IMM, +/*  0xa2 */ x86emuOp_mov_M_AL_IMM, +/*  0xa3 */ x86emuOp_mov_M_AX_IMM, +/*  0xa4 */ x86emuOp_movs_byte, +/*  0xa5 */ x86emuOp_movs_word, +/*  0xa6 */ x86emuOp_cmps_byte, +/*  0xa7 */ x86emuOp_cmps_word, +/*  0xa8 */ x86emuOp_test_AL_IMM, +/*  0xa9 */ x86emuOp_test_AX_IMM, +/*  0xaa */ x86emuOp_stos_byte, +/*  0xab */ x86emuOp_stos_word, +/*  0xac */ x86emuOp_lods_byte, +/*  0xad */ x86emuOp_lods_word, +/*  0xac */ x86emuOp_scas_byte, +/*  0xad */ x86emuOp_scas_word, + +/*  0xb0 */ x86emuOp_mov_byte_register_IMM, +/*  0xb1 */ x86emuOp_mov_byte_register_IMM, +/*  0xb2 */ x86emuOp_mov_byte_register_IMM, +/*  0xb3 */ x86emuOp_mov_byte_register_IMM, +/*  0xb4 */ x86emuOp_mov_byte_register_IMM, +/*  0xb5 */ x86emuOp_mov_byte_register_IMM, +/*  0xb6 */ x86emuOp_mov_byte_register_IMM, +/*  0xb7 */ x86emuOp_mov_byte_register_IMM, + +/*  0xb8 */ x86emuOp_mov_word_register_IMM, +/*  0xb9 */ x86emuOp_mov_word_register_IMM, +/*  0xba */ x86emuOp_mov_word_register_IMM, +/*  0xbb */ x86emuOp_mov_word_register_IMM, +/*  0xbc */ x86emuOp_mov_word_register_IMM, +/*  0xbd */ x86emuOp_mov_word_register_IMM, +/*  0xbe */ x86emuOp_mov_word_register_IMM, +/*  0xbf */ x86emuOp_mov_word_register_IMM, + +/*  0xc0 */ x86emuOp_opcC0_byte_RM_MEM, +/*  0xc1 */ x86emuOp_opcC1_word_RM_MEM, +/*  0xc2 */ x86emuOp_ret_near_IMM, +/*  0xc3 */ x86emuOp_ret_near, +/*  0xc4 */ x86emuOp_les_R_IMM, +/*  0xc5 */ x86emuOp_lds_R_IMM, +/*  0xc6 */ x86emuOp_mov_byte_RM_IMM, +/*  0xc7 */ x86emuOp_mov_word_RM_IMM, +/*  0xc8 */ x86emuOp_enter, +/*  0xc9 */ x86emuOp_leave, +/*  0xca */ x86emuOp_ret_far_IMM, +/*  0xcb */ x86emuOp_ret_far, +/*  0xcc */ x86emuOp_int3, +/*  0xcd */ x86emuOp_int_IMM, +/*  0xce */ x86emuOp_into, +/*  0xcf */ x86emuOp_iret, + +/*  0xd0 */ x86emuOp_opcD0_byte_RM_1, +/*  0xd1 */ x86emuOp_opcD1_word_RM_1, +/*  0xd2 */ x86emuOp_opcD2_byte_RM_CL, +/*  0xd3 */ x86emuOp_opcD3_word_RM_CL, +/*  0xd4 */ x86emuOp_aam, +/*  0xd5 */ x86emuOp_aad, +/*  0xd6 */ x86emuOp_illegal_op,   /* Undocumented SETALC instruction */ +/*  0xd7 */ x86emuOp_xlat, +/*  0xd8 */ NULL, /*x86emuOp_esc_coprocess_d8,*/ +/*  0xd9 */ NULL, /*x86emuOp_esc_coprocess_d9,*/ +/*  0xda */ NULL, /*x86emuOp_esc_coprocess_da,*/ +/*  0xdb */ NULL, /*x86emuOp_esc_coprocess_db,*/ +/*  0xdc */ NULL, /*x86emuOp_esc_coprocess_dc,*/ +/*  0xdd */ NULL, /*x86emuOp_esc_coprocess_dd,*/ +/*  0xde */ NULL, /*x86emuOp_esc_coprocess_de,*/ +/*  0xdf */ NULL, /*x86emuOp_esc_coprocess_df,*/ + +/*  0xe0 */ x86emuOp_loopne, +/*  0xe1 */ x86emuOp_loope, +/*  0xe2 */ x86emuOp_loop, +/*  0xe3 */ x86emuOp_jcxz, +/*  0xe4 */ x86emuOp_in_byte_AL_IMM, +/*  0xe5 */ x86emuOp_in_word_AX_IMM, +/*  0xe6 */ x86emuOp_out_byte_IMM_AL, +/*  0xe7 */ x86emuOp_out_word_IMM_AX, + +/*  0xe8 */ x86emuOp_call_near_IMM, +/*  0xe9 */ x86emuOp_jump_near_IMM, +/*  0xea */ x86emuOp_jump_far_IMM, +/*  0xeb */ x86emuOp_jump_byte_IMM, +/*  0xec */ x86emuOp_in_byte_AL_DX, +/*  0xed */ x86emuOp_in_word_AX_DX, +/*  0xee */ x86emuOp_out_byte_DX_AL, +/*  0xef */ x86emuOp_out_word_DX_AX, + +/*  0xf0 */ x86emuOp_lock, +/*  0xf1 */ x86emuOp_illegal_op, +/*  0xf2 */ x86emuOp_repne, +/*  0xf3 */ x86emuOp_repe, +/*  0xf4 */ x86emuOp_halt, +/*  0xf5 */ x86emuOp_cmc, +/*  0xf6 */ x86emuOp_opcF6_byte_RM, +/*  0xf7 */ x86emuOp_opcF7_word_RM, + +/*  0xf8 */ x86emuOp_clc, +/*  0xf9 */ x86emuOp_stc, +/*  0xfa */ x86emuOp_cli, +/*  0xfb */ x86emuOp_sti, +/*  0xfc */ x86emuOp_cld, +/*  0xfd */ x86emuOp_std, +/*  0xfe */ x86emuOp_opcFE_byte_RM, +/*  0xff */ x86emuOp_opcFF_word_RM, +}; diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c new file mode 100644 index 000000000..2412b24cd --- /dev/null +++ b/drivers/bios_emulator/x86emu/ops2.c @@ -0,0 +1,1770 @@ +/**************************************************************************** +* +*                       Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*               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 extended two-byte processor +*               instructions. +* +*               Jason port this file to u-boot. Put the function pointer into +*               got2 sector. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +op1 - Instruction op code + +REMARKS: +Handles illegal opcodes. +****************************************************************************/ +void x86emuOp2_illegal_op( +    u8 op2) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); +    TRACE_REGS(); +    printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n", +        M.x86.R_CS, M.x86.R_IP-2,op2); +    HALT_SYS(); +    END_OF_INSTR(); +} + +#define xorl(a,b)   ((a) && !(b)) || (!(a) && (b)) + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x80-0x8F +****************************************************************************/ +int x86emu_check_jump_condition(u8 op) +{ +    switch (op) { +      case 0x0: +        DECODE_PRINTF("JO\t"); +        return ACCESS_FLAG(F_OF); +      case 0x1: +        DECODE_PRINTF("JNO\t"); +        return !ACCESS_FLAG(F_OF); +        break; +      case 0x2: +        DECODE_PRINTF("JB\t"); +        return ACCESS_FLAG(F_CF); +        break; +      case 0x3: +        DECODE_PRINTF("JNB\t"); +        return !ACCESS_FLAG(F_CF); +        break; +      case 0x4: +        DECODE_PRINTF("JZ\t"); +        return ACCESS_FLAG(F_ZF); +        break; +      case 0x5: +        DECODE_PRINTF("JNZ\t"); +        return !ACCESS_FLAG(F_ZF); +        break; +      case 0x6: +        DECODE_PRINTF("JBE\t"); +        return ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); +        break; +      case 0x7: +        DECODE_PRINTF("JNBE\t"); +        return !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); +        break; +      case 0x8: +        DECODE_PRINTF("JS\t"); +        return ACCESS_FLAG(F_SF); +        break; +      case 0x9: +        DECODE_PRINTF("JNS\t"); +        return !ACCESS_FLAG(F_SF); +        break; +      case 0xa: +        DECODE_PRINTF("JP\t"); +        return ACCESS_FLAG(F_PF); +        break; +      case 0xb: +        DECODE_PRINTF("JNP\t"); +        return !ACCESS_FLAG(F_PF); +        break; +      case 0xc: +        DECODE_PRINTF("JL\t"); +        return xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0xd: +        DECODE_PRINTF("JNL\t"); +        return !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0xe: +        DECODE_PRINTF("JLE\t"); +        return (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                ACCESS_FLAG(F_ZF)); +        break; +      default: +        DECODE_PRINTF("JNLE\t"); +        return !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                 ACCESS_FLAG(F_ZF)); +    } +} + +void x86emuOp2_long_jump(u8 op2) +{ +    s32 target; +    int cond; + +    /* conditional jump to word offset. */ +    START_OF_INSTR(); +    cond = x86emu_check_jump_condition(op2 & 0xF); +    target = (s16) fetch_word_imm(); +    target += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", target); +    TRACE_AND_STEP(); +    if (cond) +        M.x86.R_IP = (u16)target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x90-0x9F +****************************************************************************/ +void x86emuOp2_set_byte(u8 op2) +{ +    int mod, rl, rh; +    uint destoffset; +    u8  *destreg; +    char *name = 0; +    int cond = 0; + +    START_OF_INSTR(); +    switch (op2) { +      case 0x90: +        name = "SETO\t"; +        cond =  ACCESS_FLAG(F_OF); +        break; +      case 0x91: +        name = "SETNO\t"; +        cond = !ACCESS_FLAG(F_OF); +        break; +      case 0x92: +        name = "SETB\t"; +        cond = ACCESS_FLAG(F_CF); +        break; +      case 0x93: +        name = "SETNB\t"; +        cond = !ACCESS_FLAG(F_CF); +        break; +      case 0x94: +        name = "SETZ\t"; +        cond = ACCESS_FLAG(F_ZF); +        break; +      case 0x95: +        name = "SETNZ\t"; +        cond = !ACCESS_FLAG(F_ZF); +        break; +      case 0x96: +        name = "SETBE\t"; +        cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); +        break; +      case 0x97: +        name = "SETNBE\t"; +        cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); +        break; +      case 0x98: +        name = "SETS\t"; +        cond = ACCESS_FLAG(F_SF); +        break; +      case 0x99: +        name = "SETNS\t"; +        cond = !ACCESS_FLAG(F_SF); +        break; +      case 0x9a: +        name = "SETP\t"; +        cond = ACCESS_FLAG(F_PF); +        break; +      case 0x9b: +        name = "SETNP\t"; +        cond = !ACCESS_FLAG(F_PF); +        break; +      case 0x9c: +        name = "SETL\t"; +        cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0x9d: +        name = "SETNL\t"; +        cond = !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0x9e: +        name = "SETLE\t"; +        cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                ACCESS_FLAG(F_ZF)); +        break; +      case 0x9f: +        name = "SETNLE\t"; +        cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                 ACCESS_FLAG(F_ZF)); +        break; +    } +    DECODE_PRINTF(name); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        TRACE_AND_STEP(); +        store_data_byte(destoffset, cond ? 0x01 : 0x00); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        TRACE_AND_STEP(); +        *destreg = cond ? 0x01 : 0x00; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa0 +****************************************************************************/ +void x86emuOp2_push_FS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tFS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_FS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa1 +****************************************************************************/ +void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tFS\n"); +    TRACE_AND_STEP(); +    M.x86.R_FS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa3 +****************************************************************************/ +void x86emuOp2_bt_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BT\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); +        } else { +            u16 srcval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); +        } else { +            u16 *srcreg,*shiftreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa4 +****************************************************************************/ +void x86emuOp2_shld_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 shift; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\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 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shld_long(destval,*shiftreg,shift); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shld_word(destval,*shiftreg,shift); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shld_long(*destreg,*shiftreg,shift); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shld_word(*destreg,*shiftreg,shift); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa5 +****************************************************************************/ +void x86emuOp2_shld_CL(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\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 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shld_long(destval,*shiftreg,M.x86.R_CL); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shld_word(destval,*shiftreg,M.x86.R_CL); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shld_long(*destreg,*shiftreg,M.x86.R_CL); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shld_word(*destreg,*shiftreg,M.x86.R_CL); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa8 +****************************************************************************/ +void x86emuOp2_push_GS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tGS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_GS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa9 +****************************************************************************/ +void x86emuOp2_pop_GS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tGS\n"); +    TRACE_AND_STEP(); +    M.x86.R_GS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaa +****************************************************************************/ +void x86emuOp2_bts_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval | mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, srcval | mask); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg |= mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg |= mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xac +****************************************************************************/ +void x86emuOp2_shrd_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 shift; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\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 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shrd_long(destval,*shiftreg,shift); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shrd_word(destval,*shiftreg,shift); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shrd_long(*destreg,*shiftreg,shift); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shrd_word(*destreg,*shiftreg,shift); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xad +****************************************************************************/ +void x86emuOp2_shrd_CL(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\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 destval; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shrd_long(destval,*shiftreg,M.x86.R_CL); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shrd_word(destval,*shiftreg,M.x86.R_CL); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shrd_word(*destreg,*shiftreg,M.x86.R_CL); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaf +****************************************************************************/ +void x86emuOp2_imul_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("IMUL\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; +            u32 res_lo,res_hi; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_long(srcoffset); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval); +            if (res_hi != 0) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg; +            u16 srcval; +            u32 res; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_word(srcoffset); +            TRACE_AND_STEP(); +            res = (s16)*destreg * (s16)srcval; +            if (res > 0xFFFF) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_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); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)*srcreg); +            if (res_hi != 0) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_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); +            res = (s16)*destreg * (s16)*srcreg; +            if (res > 0xFFFF) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb2 +****************************************************************************/ +void x86emuOp2_lss_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LSS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_SS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb3 +****************************************************************************/ +void x86emuOp2_btr_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTR\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval & ~mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, (u16)(srcval & ~mask)); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg &= ~mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg &= ~mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb4 +****************************************************************************/ +void x86emuOp2_lfs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LFS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_FS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb5 +****************************************************************************/ +void x86emuOp2_lgs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LGS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_GS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb6 +****************************************************************************/ +void x86emuOp2_movzx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVZX\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_byte(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_byte(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } else { +            u16 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_WORD_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 0x0f,0xb7 +****************************************************************************/ +void x86emuOp2_movzx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u32 *destreg; +    u32 srcval; +    u16 *srcreg; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVZX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_LONG_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_LONG_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 0x0f,0xba +****************************************************************************/ +void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u8 shift; +    int bit; + +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    switch (rh) { +    case 4: +        DECODE_PRINTF("BT\t"); +        break; +    case 5: +        DECODE_PRINTF("BTS\t"); +        break; +    case 6: +        DECODE_PRINTF("BTR\t"); +        break; +    case 7: +        DECODE_PRINTF("BTC\t"); +        break; +    default: +        DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); +        TRACE_REGS(); +        printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n", +                M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl); +        HALT_SYS(); +    } +    if (mod < 3) { + +        srcoffset = decode_rmXX_address(mod, rl); +        shift = fetch_byte_imm(); +        DECODE_PRINTF2(",%d\n", shift); +        TRACE_AND_STEP(); + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, mask; + +            bit = shift & 0x1F; +            srcval = fetch_data_long(srcoffset); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            switch (rh) { +            case 5: +                store_data_long(srcoffset, srcval | mask); +                break; +            case 6: +                store_data_long(srcoffset, srcval & ~mask); +                break; +            case 7: +                store_data_long(srcoffset, srcval ^ mask); +                break; +            default: +                break; +            } +        } else { +            u16 srcval, mask; + +            bit = shift & 0xF; +            srcval = fetch_data_word(srcoffset); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            switch (rh) { +            case 5: +                store_data_word(srcoffset, srcval | mask); +                break; +            case 6: +                store_data_word(srcoffset, srcval & ~mask); +                break; +            case 7: +                store_data_word(srcoffset, srcval ^ mask); +                break; +            default: +                break; +            } +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", shift); +            TRACE_AND_STEP(); +            bit = shift & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            switch (rh) { +            case 5: +                *srcreg |= mask; +                break; +            case 6: +                *srcreg &= ~mask; +                break; +            case 7: +                *srcreg ^= mask; +                break; +            default: +                break; +            } +        } else { +            u16 *srcreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", shift); +            TRACE_AND_STEP(); +            bit = shift & 0xF; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            switch (rh) { +            case 5: +                *srcreg |= mask; +                break; +            case 6: +                *srcreg &= ~mask; +                break; +            case 7: +                *srcreg ^= mask; +                break; +            default: +                break; +            } +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbb +****************************************************************************/ +void x86emuOp2_btc_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTC\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval ^ mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, (u16)(srcval ^ mask)); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg ^= mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg ^= mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbc +****************************************************************************/ +void x86emuOp2_bsf(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("BSF\n"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, *dstreg; + +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_long(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 32; (*dstreg)++) +                if ((srcval >> *dstreg) & 1) break; +        } else { +            u16 srcval, *dstreg; + +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_word(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 16; (*dstreg)++) +                if ((srcval >> *dstreg) & 1) break; +        } +    } else {             /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg, *dstreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 32; (*dstreg)++) +                if ((*srcreg >> *dstreg) & 1) break; +        } else { +            u16 *srcreg, *dstreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 16; (*dstreg)++) +                if ((*srcreg >> *dstreg) & 1) break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbd +****************************************************************************/ +void x86emuOp2_bsr(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("BSF\n"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, *dstreg; + +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_long(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 31; *dstreg > 0; (*dstreg)--) +                if ((srcval >> *dstreg) & 1) break; +        } else { +            u16 srcval, *dstreg; + +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_word(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 15; *dstreg > 0; (*dstreg)--) +                if ((srcval >> *dstreg) & 1) break; +        } +    } else {             /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg, *dstreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 31; *dstreg > 0; (*dstreg)--) +                if ((*srcreg >> *dstreg) & 1) break; +        } else { +            u16 *srcreg, *dstreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 15; *dstreg > 0; (*dstreg)--) +                if ((*srcreg >> *dstreg) & 1) break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbe +****************************************************************************/ +void x86emuOp2_movsx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVSX\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 = (s32)((s8)fetch_data_byte(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 = (s16)((s8)fetch_data_byte(srcoffset)); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = (s32)((s8)*srcreg); +        } else { +            u16 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = (s16)((s8)*srcreg); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbf +****************************************************************************/ +void x86emuOp2_movsx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u32 *destreg; +    u32 srcval; +    u16 *srcreg; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVSX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        srcval = (s32)((s16)fetch_data_word(srcoffset)); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = srcval; +    } else {                     /* register to register */ +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_WORD_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = (s32)((s16)*srcreg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*************************************************************************** + * Double byte operation code table: + **************************************************************************/ +void (*x86emu_optab2[256])(u8) __attribute__((section(".got2"))) = +{ +/*  0x00 */ x86emuOp2_illegal_op,  /* Group F (ring 0 PM)      */ +/*  0x01 */ x86emuOp2_illegal_op,  /* Group G (ring 0 PM)      */ +/*  0x02 */ x86emuOp2_illegal_op,  /* lar (ring 0 PM)          */ +/*  0x03 */ x86emuOp2_illegal_op,  /* lsl (ring 0 PM)          */ +/*  0x04 */ x86emuOp2_illegal_op, +/*  0x05 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */ +/*  0x06 */ x86emuOp2_illegal_op,  /* clts (ring 0 PM)         */ +/*  0x07 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */ +/*  0x08 */ x86emuOp2_illegal_op,  /* invd (ring 0 PM)         */ +/*  0x09 */ x86emuOp2_illegal_op,  /* wbinvd (ring 0 PM)       */ +/*  0x0a */ x86emuOp2_illegal_op, +/*  0x0b */ x86emuOp2_illegal_op, +/*  0x0c */ x86emuOp2_illegal_op, +/*  0x0d */ x86emuOp2_illegal_op, +/*  0x0e */ x86emuOp2_illegal_op, +/*  0x0f */ x86emuOp2_illegal_op, + +/*  0x10 */ x86emuOp2_illegal_op, +/*  0x11 */ x86emuOp2_illegal_op, +/*  0x12 */ x86emuOp2_illegal_op, +/*  0x13 */ x86emuOp2_illegal_op, +/*  0x14 */ x86emuOp2_illegal_op, +/*  0x15 */ x86emuOp2_illegal_op, +/*  0x16 */ x86emuOp2_illegal_op, +/*  0x17 */ x86emuOp2_illegal_op, +/*  0x18 */ x86emuOp2_illegal_op, +/*  0x19 */ x86emuOp2_illegal_op, +/*  0x1a */ x86emuOp2_illegal_op, +/*  0x1b */ x86emuOp2_illegal_op, +/*  0x1c */ x86emuOp2_illegal_op, +/*  0x1d */ x86emuOp2_illegal_op, +/*  0x1e */ x86emuOp2_illegal_op, +/*  0x1f */ x86emuOp2_illegal_op, + +/*  0x20 */ x86emuOp2_illegal_op,  /* mov reg32,creg (ring 0 PM) */ +/*  0x21 */ x86emuOp2_illegal_op,  /* mov reg32,dreg (ring 0 PM) */ +/*  0x22 */ x86emuOp2_illegal_op,  /* mov creg,reg32 (ring 0 PM) */ +/*  0x23 */ x86emuOp2_illegal_op,  /* mov dreg,reg32 (ring 0 PM) */ +/*  0x24 */ x86emuOp2_illegal_op,  /* mov reg32,treg (ring 0 PM) */ +/*  0x25 */ x86emuOp2_illegal_op, +/*  0x26 */ x86emuOp2_illegal_op,  /* mov treg,reg32 (ring 0 PM) */ +/*  0x27 */ x86emuOp2_illegal_op, +/*  0x28 */ x86emuOp2_illegal_op, +/*  0x29 */ x86emuOp2_illegal_op, +/*  0x2a */ x86emuOp2_illegal_op, +/*  0x2b */ x86emuOp2_illegal_op, +/*  0x2c */ x86emuOp2_illegal_op, +/*  0x2d */ x86emuOp2_illegal_op, +/*  0x2e */ x86emuOp2_illegal_op, +/*  0x2f */ x86emuOp2_illegal_op, + +/*  0x30 */ x86emuOp2_illegal_op, +/*  0x31 */ x86emuOp2_illegal_op, +/*  0x32 */ x86emuOp2_illegal_op, +/*  0x33 */ x86emuOp2_illegal_op, +/*  0x34 */ x86emuOp2_illegal_op, +/*  0x35 */ x86emuOp2_illegal_op, +/*  0x36 */ x86emuOp2_illegal_op, +/*  0x37 */ x86emuOp2_illegal_op, +/*  0x38 */ x86emuOp2_illegal_op, +/*  0x39 */ x86emuOp2_illegal_op, +/*  0x3a */ x86emuOp2_illegal_op, +/*  0x3b */ x86emuOp2_illegal_op, +/*  0x3c */ x86emuOp2_illegal_op, +/*  0x3d */ x86emuOp2_illegal_op, +/*  0x3e */ x86emuOp2_illegal_op, +/*  0x3f */ x86emuOp2_illegal_op, + +/*  0x40 */ x86emuOp2_illegal_op, +/*  0x41 */ x86emuOp2_illegal_op, +/*  0x42 */ x86emuOp2_illegal_op, +/*  0x43 */ x86emuOp2_illegal_op, +/*  0x44 */ x86emuOp2_illegal_op, +/*  0x45 */ x86emuOp2_illegal_op, +/*  0x46 */ x86emuOp2_illegal_op, +/*  0x47 */ x86emuOp2_illegal_op, +/*  0x48 */ x86emuOp2_illegal_op, +/*  0x49 */ x86emuOp2_illegal_op, +/*  0x4a */ x86emuOp2_illegal_op, +/*  0x4b */ x86emuOp2_illegal_op, +/*  0x4c */ x86emuOp2_illegal_op, +/*  0x4d */ x86emuOp2_illegal_op, +/*  0x4e */ x86emuOp2_illegal_op, +/*  0x4f */ x86emuOp2_illegal_op, + +/*  0x50 */ x86emuOp2_illegal_op, +/*  0x51 */ x86emuOp2_illegal_op, +/*  0x52 */ x86emuOp2_illegal_op, +/*  0x53 */ x86emuOp2_illegal_op, +/*  0x54 */ x86emuOp2_illegal_op, +/*  0x55 */ x86emuOp2_illegal_op, +/*  0x56 */ x86emuOp2_illegal_op, +/*  0x57 */ x86emuOp2_illegal_op, +/*  0x58 */ x86emuOp2_illegal_op, +/*  0x59 */ x86emuOp2_illegal_op, +/*  0x5a */ x86emuOp2_illegal_op, +/*  0x5b */ x86emuOp2_illegal_op, +/*  0x5c */ x86emuOp2_illegal_op, +/*  0x5d */ x86emuOp2_illegal_op, +/*  0x5e */ x86emuOp2_illegal_op, +/*  0x5f */ x86emuOp2_illegal_op, + +/*  0x60 */ x86emuOp2_illegal_op, +/*  0x61 */ x86emuOp2_illegal_op, +/*  0x62 */ x86emuOp2_illegal_op, +/*  0x63 */ x86emuOp2_illegal_op, +/*  0x64 */ x86emuOp2_illegal_op, +/*  0x65 */ x86emuOp2_illegal_op, +/*  0x66 */ x86emuOp2_illegal_op, +/*  0x67 */ x86emuOp2_illegal_op, +/*  0x68 */ x86emuOp2_illegal_op, +/*  0x69 */ x86emuOp2_illegal_op, +/*  0x6a */ x86emuOp2_illegal_op, +/*  0x6b */ x86emuOp2_illegal_op, +/*  0x6c */ x86emuOp2_illegal_op, +/*  0x6d */ x86emuOp2_illegal_op, +/*  0x6e */ x86emuOp2_illegal_op, +/*  0x6f */ x86emuOp2_illegal_op, + +/*  0x70 */ x86emuOp2_illegal_op, +/*  0x71 */ x86emuOp2_illegal_op, +/*  0x72 */ x86emuOp2_illegal_op, +/*  0x73 */ x86emuOp2_illegal_op, +/*  0x74 */ x86emuOp2_illegal_op, +/*  0x75 */ x86emuOp2_illegal_op, +/*  0x76 */ x86emuOp2_illegal_op, +/*  0x77 */ x86emuOp2_illegal_op, +/*  0x78 */ x86emuOp2_illegal_op, +/*  0x79 */ x86emuOp2_illegal_op, +/*  0x7a */ x86emuOp2_illegal_op, +/*  0x7b */ x86emuOp2_illegal_op, +/*  0x7c */ x86emuOp2_illegal_op, +/*  0x7d */ x86emuOp2_illegal_op, +/*  0x7e */ x86emuOp2_illegal_op, +/*  0x7f */ x86emuOp2_illegal_op, + +/*  0x80 */ x86emuOp2_long_jump, +/*  0x81 */ x86emuOp2_long_jump, +/*  0x82 */ x86emuOp2_long_jump, +/*  0x83 */ x86emuOp2_long_jump, +/*  0x84 */ x86emuOp2_long_jump, +/*  0x85 */ x86emuOp2_long_jump, +/*  0x86 */ x86emuOp2_long_jump, +/*  0x87 */ x86emuOp2_long_jump, +/*  0x88 */ x86emuOp2_long_jump, +/*  0x89 */ x86emuOp2_long_jump, +/*  0x8a */ x86emuOp2_long_jump, +/*  0x8b */ x86emuOp2_long_jump, +/*  0x8c */ x86emuOp2_long_jump, +/*  0x8d */ x86emuOp2_long_jump, +/*  0x8e */ x86emuOp2_long_jump, +/*  0x8f */ x86emuOp2_long_jump, + +/*  0x90 */ x86emuOp2_set_byte, +/*  0x91 */ x86emuOp2_set_byte, +/*  0x92 */ x86emuOp2_set_byte, +/*  0x93 */ x86emuOp2_set_byte, +/*  0x94 */ x86emuOp2_set_byte, +/*  0x95 */ x86emuOp2_set_byte, +/*  0x96 */ x86emuOp2_set_byte, +/*  0x97 */ x86emuOp2_set_byte, +/*  0x98 */ x86emuOp2_set_byte, +/*  0x99 */ x86emuOp2_set_byte, +/*  0x9a */ x86emuOp2_set_byte, +/*  0x9b */ x86emuOp2_set_byte, +/*  0x9c */ x86emuOp2_set_byte, +/*  0x9d */ x86emuOp2_set_byte, +/*  0x9e */ x86emuOp2_set_byte, +/*  0x9f */ x86emuOp2_set_byte, + +/*  0xa0 */ x86emuOp2_push_FS, +/*  0xa1 */ x86emuOp2_pop_FS, +/*  0xa2 */ x86emuOp2_illegal_op, +/*  0xa3 */ x86emuOp2_bt_R, +/*  0xa4 */ x86emuOp2_shld_IMM, +/*  0xa5 */ x86emuOp2_shld_CL, +/*  0xa6 */ x86emuOp2_illegal_op, +/*  0xa7 */ x86emuOp2_illegal_op, +/*  0xa8 */ x86emuOp2_push_GS, +/*  0xa9 */ x86emuOp2_pop_GS, +/*  0xaa */ x86emuOp2_illegal_op, +/*  0xab */ x86emuOp2_bt_R, +/*  0xac */ x86emuOp2_shrd_IMM, +/*  0xad */ x86emuOp2_shrd_CL, +/*  0xae */ x86emuOp2_illegal_op, +/*  0xaf */ x86emuOp2_imul_R_RM, + +/*  0xb0 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */ +/*  0xb1 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */ +/*  0xb2 */ x86emuOp2_lss_R_IMM, +/*  0xb3 */ x86emuOp2_btr_R, +/*  0xb4 */ x86emuOp2_lfs_R_IMM, +/*  0xb5 */ x86emuOp2_lgs_R_IMM, +/*  0xb6 */ x86emuOp2_movzx_byte_R_RM, +/*  0xb7 */ x86emuOp2_movzx_word_R_RM, +/*  0xb8 */ x86emuOp2_illegal_op, +/*  0xb9 */ x86emuOp2_illegal_op, +/*  0xba */ x86emuOp2_btX_I, +/*  0xbb */ x86emuOp2_btc_R, +/*  0xbc */ x86emuOp2_bsf, +/*  0xbd */ x86emuOp2_bsr, +/*  0xbe */ x86emuOp2_movsx_byte_R_RM, +/*  0xbf */ x86emuOp2_movsx_word_R_RM, + +/*  0xc0 */ x86emuOp2_illegal_op,  /* TODO: xadd */ +/*  0xc1 */ x86emuOp2_illegal_op,  /* TODO: xadd */ +/*  0xc2 */ x86emuOp2_illegal_op, +/*  0xc3 */ x86emuOp2_illegal_op, +/*  0xc4 */ x86emuOp2_illegal_op, +/*  0xc5 */ x86emuOp2_illegal_op, +/*  0xc6 */ x86emuOp2_illegal_op, +/*  0xc7 */ x86emuOp2_illegal_op, +/*  0xc8 */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xc9 */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xca */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcb */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcc */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcd */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xce */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcf */ x86emuOp2_illegal_op,  /* TODO: bswap */ + +/*  0xd0 */ x86emuOp2_illegal_op, +/*  0xd1 */ x86emuOp2_illegal_op, +/*  0xd2 */ x86emuOp2_illegal_op, +/*  0xd3 */ x86emuOp2_illegal_op, +/*  0xd4 */ x86emuOp2_illegal_op, +/*  0xd5 */ x86emuOp2_illegal_op, +/*  0xd6 */ x86emuOp2_illegal_op, +/*  0xd7 */ x86emuOp2_illegal_op, +/*  0xd8 */ x86emuOp2_illegal_op, +/*  0xd9 */ x86emuOp2_illegal_op, +/*  0xda */ x86emuOp2_illegal_op, +/*  0xdb */ x86emuOp2_illegal_op, +/*  0xdc */ x86emuOp2_illegal_op, +/*  0xdd */ x86emuOp2_illegal_op, +/*  0xde */ x86emuOp2_illegal_op, +/*  0xdf */ x86emuOp2_illegal_op, + +/*  0xe0 */ x86emuOp2_illegal_op, +/*  0xe1 */ x86emuOp2_illegal_op, +/*  0xe2 */ x86emuOp2_illegal_op, +/*  0xe3 */ x86emuOp2_illegal_op, +/*  0xe4 */ x86emuOp2_illegal_op, +/*  0xe5 */ x86emuOp2_illegal_op, +/*  0xe6 */ x86emuOp2_illegal_op, +/*  0xe7 */ x86emuOp2_illegal_op, +/*  0xe8 */ x86emuOp2_illegal_op, +/*  0xe9 */ x86emuOp2_illegal_op, +/*  0xea */ x86emuOp2_illegal_op, +/*  0xeb */ x86emuOp2_illegal_op, +/*  0xec */ x86emuOp2_illegal_op, +/*  0xed */ x86emuOp2_illegal_op, +/*  0xee */ x86emuOp2_illegal_op, +/*  0xef */ x86emuOp2_illegal_op, + +/*  0xf0 */ x86emuOp2_illegal_op, +/*  0xf1 */ x86emuOp2_illegal_op, +/*  0xf2 */ x86emuOp2_illegal_op, +/*  0xf3 */ x86emuOp2_illegal_op, +/*  0xf4 */ x86emuOp2_illegal_op, +/*  0xf5 */ x86emuOp2_illegal_op, +/*  0xf6 */ x86emuOp2_illegal_op, +/*  0xf7 */ x86emuOp2_illegal_op, +/*  0xf8 */ x86emuOp2_illegal_op, +/*  0xf9 */ x86emuOp2_illegal_op, +/*  0xfa */ x86emuOp2_illegal_op, +/*  0xfb */ x86emuOp2_illegal_op, +/*  0xfc */ x86emuOp2_illegal_op, +/*  0xfd */ x86emuOp2_illegal_op, +/*  0xfe */ x86emuOp2_illegal_op, +/*  0xff */ x86emuOp2_illegal_op, +}; diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c new file mode 100644 index 000000000..dc8cea800 --- /dev/null +++ b/drivers/bios_emulator/x86emu/prim_ops.c @@ -0,0 +1,2446 @@ +/**************************************************************************** +* +*                       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 contains the code to implement the primitive +*               machine operations used by the emulation code in ops.c +* +* Carry Chain Calculation +* +* This represents a somewhat expensive calculation which is +* apparently required to emulate the setting of the OF343364 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) +* +****************************************************************************/ + +#define PRIM_OPS_NO_REDEFINE_ASM +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +static u32 x86emu_parity_tab[8] = +{ +    0x96696996, +    0x69969669, +    0x69969669, +    0x96696996, +    0x69969669, +    0x96696996, +    0x96696996, +    0x69969669, +}; + +#define PARITY(x)   (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define XOR2(x)     (((x) ^ ((x)>>1)) & 0x1) +/*----------------------------- Implementation ----------------------------*/ +int abs(int v) +{ +	return (v>0)?v:-v; +} + +/*----------------------------- Implementation ----------------------------*/ + + +/*--------- Side effects helper functions -------*/ + +/**************************************************************************** +REMARKS: +implements side efects for byte operations that don't overflow +****************************************************************************/ + +static void set_parity_flag(u32 res) +{ +    CONDITIONAL_SET_FLAG(PARITY(res & 0xFF), F_PF); +} + +static void set_szp_flags_8(u8 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_16(u16 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_32(u32 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void no_carry_byte_side_eff(u8 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_8(res); +} + +static void no_carry_word_side_eff(u16 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_16(res); +} + +static void no_carry_long_side_eff(u32 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_32(res); +} + +static void calc_carry_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 cc; + +    cc = (s & d) | ((~res) & (s | d)); +    CONDITIONAL_SET_FLAG(XOR2(cc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(res & (1 << bits), F_CF); +    } +} + +static void calc_borrow_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 bc; + +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(XOR2(bc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(bc & (1 << (bits - 1)), F_CF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aaa_word(u16 d) +{ +    u16 res; +    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { +        d += 0x6; +        d += 0x100; +        SET_FLAG(F_AF); +        SET_FLAG(F_CF); +    } else { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_AF); +    } +    res = (u16)(d & 0xFF0F); +    set_szp_flags_16(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aas_word(u16 d) +{ +    u16 res; +    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { +        d -= 0x6; +        d -= 0x100; +        SET_FLAG(F_AF); +        SET_FLAG(F_CF); +    } else { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_AF); +    } +    res = (u16)(d & 0xFF0F); +    set_szp_flags_16(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAD instruction and side effects. +****************************************************************************/ +u16 aad_word(u16 d) +{ +    u16 l; +    u8 hb, lb; + +    hb = (u8)((d >> 8) & 0xff); +    lb = (u8)((d & 0xff)); +    l = (u16)((lb + 10 * hb) & 0xFF); + +    no_carry_byte_side_eff(l & 0xFF); +    return l; +} + +/**************************************************************************** +REMARKS: +Implements the AAM instruction and side effects. +****************************************************************************/ +u16 aam_word(u8 d) +{ +    u16 h, l; + +    h = (u16)(d / 10); +    l = (u16)(d % 10); +    l |= (u16)(h << 8); + +    no_carry_byte_side_eff(l & 0xFF); +    return l; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u8 adc_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) res++; + +    set_szp_flags_8(res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u16 adc_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) +        res++; + +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u32 adc_long(u32 d, u32 s) +{ +    u32 lo;    /* all operands in native machine order */ +    u32 hi; +    u32 res; + +    lo = (d & 0xFFFF) + (s & 0xFFFF); +    res = d + s; + +    if (ACCESS_FLAG(F_CF)) { +        lo++; +        res++; +    } + +    hi = (lo >> 16) + (d >> 16) + (s >> 16); + +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u8 add_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u16 add_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u32 add_long(u32 d, u32 s) +{ +    u32 res; + +    res = d + s; +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(res < d || res < s, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u8 and_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d & s; + +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u16 and_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d & s; + +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u32 and_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u8 cmp_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u16 cmp_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u32 cmp_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the DAA instruction and side effects. +****************************************************************************/ +u8 daa_byte(u8 d) +{ +    u32 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); +    } +    set_szp_flags_8((u8)res); +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DAS instruction and side effects. +****************************************************************************/ +u8 das_byte(u8 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); +    } +    set_szp_flags_8(d); +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u8 dec_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u16 dec_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u32 dec_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; + +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u8 inc_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u16 inc_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u32 inc_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_32(res); +    calc_carry_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 or_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d | s; +    no_carry_byte_side_eff(res); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 or_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 or_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 neg_byte(u8 s) +{ +    u8 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u8)-s; +    set_szp_flags_8(res); +    calc_borrow_chain(8, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 neg_word(u16 s) +{ +    u16 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u16)-s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 neg_long(u32 s) +{ +    u32 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u32)-s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u8 not_byte(u8 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u16 not_word(u16 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u32 not_long(u32 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u8 rcl_byte(u8 d, u8 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u16 rcl_word(u16 d, u8 s) +{ +    unsigned int res, cnt, mask, cf; + +    res = d; +    if ((cnt = s % 17) != 0) { +        cf = (d >> (16 - cnt)) & 0x1; +        res = (d << cnt) & 0xffff; +        mask = (1 << (cnt - 1)) - 1; +        res |= (d >> (17 - cnt)) & mask; +        if (ACCESS_FLAG(F_CF)) { +            res |= 1 << (cnt - 1); +        } +        CONDITIONAL_SET_FLAG(cf, F_CF); +        CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), +                             F_OF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u32 rcl_long(u32 d, u8 s) +{ +    u32 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. +****************************************************************************/ +u8 rcr_byte(u8 d, u8 s) +{ +    u32 res, cnt; +    u32 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??? */ + +        mask = (1 << (8 - cnt)) - 1; +        res = (d >> cnt) & mask; + +        /* 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u16 rcr_word(u16 d, u8 s) +{ +    u32 res, cnt; +    u32 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u32 rcr_long(u32 d, u8 s) +{ +    u32 res, cnt; +    u32 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. +****************************************************************************/ +u8 rol_byte(u8 d, u8 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); + +        /* B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n) */ +        mask = (1 << cnt) - 1; +        res |= (d >> (8 - cnt)) & mask; + +        /* 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u16 rol_word(u16 d, u8 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u32 rol_long(u32 d, u8 s) +{ +    u32 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. +****************************************************************************/ +u8 ror_byte(u8 d, u8 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)); + +        /* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) */ +        mask = (1 << (8 - cnt)) - 1; +        res |= (d >> (cnt)) & mask; + +        /* 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u16 ror_word(u16 d, u8 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u32 ror_long(u32 d, u8 s) +{ +    u32 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. +****************************************************************************/ +u8 shl_byte(u8 d, u8 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); +            set_szp_flags_8((u8)res); +        } else { +            res = (u8) d; +        } + +        if (cnt == 1) { +            /* Needs simplification. */ +            CONDITIONAL_SET_FLAG( +                                    (((res & 0x80) == 0x80) ^ +                                     (ACCESS_FLAG(F_CF) != 0)), +            /* was (M.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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u16 shl_word(u16 d, u8 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); +            set_szp_flags_16((u16)res); +        } else { +            res = (u16) 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u32 shl_long(u32 d, u8 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); +            set_szp_flags_32((u32)res); +        } 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. +****************************************************************************/ +u8 shr_byte(u8 d, u8 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); +            set_szp_flags_8((u8)res); +        } else { +            res = (u8) 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u16 shr_word(u16 d, u8 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); +            set_szp_flags_16((u16)res); +        } 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u32 shr_long(u32 d, u8 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); +            set_szp_flags_32((u32)res); +        } 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. +****************************************************************************/ +u8 sar_byte(u8 d, u8 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; +        } +        set_szp_flags_8((u8)res); +    } 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u16 sar_word(u16 d, u8 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; +        } +        set_szp_flags_16((u16)res); +    } 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u32 sar_long(u32 d, u8 s) +{ +    u32 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; +        } +        set_szp_flags_32(res); +    } 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. +****************************************************************************/ +u16 shld_word (u16 d, u16 fill, u8 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); +            set_szp_flags_16((u16)res); +        } 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +u32 shld_long (u32 d, u32 fill, u8 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); +            set_szp_flags_32((u32)res); +        } 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. +****************************************************************************/ +u16 shrd_word (u16 d, u16 fill, u8 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); +            set_szp_flags_16((u16)res); +        } 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +u32 shrd_long (u32 d, u32 fill, u8 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); +            set_szp_flags_32((u32)res); +        } 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. +****************************************************************************/ +u8 sbb_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_8((u8)res); + +    /* 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u16 sbb_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_16((u16)res); + +    /* 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u32 sbb_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; + +    set_szp_flags_32(res); + +    /* 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. +****************************************************************************/ +u8 sub_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_8((u8)res); + +    /* 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 (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u16 sub_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_16((u16)res); + +    /* 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 (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u32 sub_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_32(res); + +    /* 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. +****************************************************************************/ +void test_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_8((u8)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_16((u16)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_32(res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u8 xor_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u16 xor_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u32 xor_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_byte(u8 s) +{ +    s16 res = (s16)((s8)M.x86.R_AL * (s8)s); + +    M.x86.R_AX = res; +    if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) || +        ((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_word(u16 s) +{ +    s32 res = (s16)M.x86.R_AX * (s16)s; + +    M.x86.R_AX = (u16)res; +    M.x86.R_DX = (u16)(res >> 16); +    if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x0000) || +        ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFFFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    s64 res = (s32)d * (s32)s; + +    *res_lo = (u32)res; +    *res_hi = (u32)(res >> 32); +#else +    u32 d_lo,d_hi,d_sign; +    u32 s_lo,s_hi,s_sign; +    u32 rlo_lo,rlo_hi,rhi_lo; + +    if ((d_sign = d & 0x80000000) != 0) +        d = -d; +    d_lo = d & 0xFFFF; +    d_hi = d >> 16; +    if ((s_sign = s & 0x80000000) != 0) +        s = -s; +    s_lo = s & 0xFFFF; +    s_hi = s >> 16; +    rlo_lo = d_lo * s_lo; +    rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16); +    rhi_lo = d_hi * s_hi + (rlo_hi >> 16); +    *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF); +    *res_hi = rhi_lo; +    if (d_sign != s_sign) { +        d = ~*res_lo; +        s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16); +        *res_lo = ~*res_lo+1; +        *res_hi = ~*res_hi+(s >> 16); +        } +#endif +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long(u32 s) +{ +    imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); +    if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00000000) || +        ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFFFFFFFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_byte(u8 s) +{ +    u16 res = (u16)(M.x86.R_AL * s); + +    M.x86.R_AX = res; +    if (M.x86.R_AH == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_word(u16 s) +{ +    u32 res = M.x86.R_AX * s; + +    M.x86.R_AX = (u16)res; +    M.x86.R_DX = (u16)(res >> 16); +    if (M.x86.R_DX == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    u64 res = (u32)M.x86.R_EAX * (u32)s; + +    M.x86.R_EAX = (u32)res; +    M.x86.R_EDX = (u32)(res >> 32); +#else +    u32 a,a_lo,a_hi; +    u32 s_lo,s_hi; +    u32 rlo_lo,rlo_hi,rhi_lo; + +    a = M.x86.R_EAX; +    a_lo = a & 0xFFFF; +    a_hi = a >> 16; +    s_lo = s & 0xFFFF; +    s_hi = s >> 16; +    rlo_lo = a_lo * s_lo; +    rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16); +    rhi_lo = a_hi * s_hi + (rlo_hi >> 16); +    M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF); +    M.x86.R_EDX = rhi_lo; +#endif +    if (M.x86.R_EDX == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_byte(u8 s) +{ +    s32 dvd, div, mod; + +    dvd = (s16)M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s8)s; +    mod = dvd % (s8)s; +    if (abs(div) > 0x7f) { +        x86emu_intr_raise(0); +        return; +    } +    M.x86.R_AL = (s8) div; +    M.x86.R_AH = (s8) mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_word(u16 s) +{ +    s32 dvd, div, mod; + +    dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s16)s; +    mod = dvd % (s16)s; +    if (abs(div) > 0x7fff) { +        x86emu_intr_raise(0); +        return; +    } +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_SF); +    CONDITIONAL_SET_FLAG(div == 0, F_ZF); +    set_parity_flag(mod); + +    M.x86.R_AX = (u16)div; +    M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    s64 dvd, div, mod; + +    dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s32)s; +    mod = dvd % (s32)s; +    if (abs(div) > 0x7fffffff) { +        x86emu_intr_raise(0); +        return; +    } +#else +    s32 div = 0, mod; +    s32 h_dvd = M.x86.R_EDX; +    u32 l_dvd = M.x86.R_EAX; +    u32 abs_s = s & 0x7FFFFFFF; +    u32 abs_h_dvd = h_dvd & 0x7FFFFFFF; +    u32 h_s = abs_s >> 1; +    u32 l_s = abs_s << 31; +    int counter = 31; +    int carry; + +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    do { +        div <<= 1; +        carry = (l_dvd >= l_s) ? 0 : 1; + +        if (abs_h_dvd < (h_s + carry)) { +            h_s >>= 1; +            l_s = abs_s << (--counter); +            continue; +        } else { +            abs_h_dvd -= (h_s + carry); +            l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) +                : (l_dvd - l_s); +            h_s >>= 1; +            l_s = abs_s << (--counter); +            div |= 1; +            continue; +        } + +    } while (counter > -1); +    /* overflow */ +    if (abs_h_dvd || (l_dvd > abs_s)) { +        x86emu_intr_raise(0); +        return; +    } +    /* sign */ +    div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000)); +    mod = l_dvd; + +#endif +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    CLEAR_FLAG(F_SF); +    SET_FLAG(F_ZF); +    set_parity_flag(mod); + +    M.x86.R_EAX = (u32)div; +    M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_byte(u8 s) +{ +    u32 dvd, div, mod; + +    dvd = M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u8)s; +    mod = dvd % (u8)s; +    if (abs(div) > 0xff) { +        x86emu_intr_raise(0); +        return; +    } +    M.x86.R_AL = (u8)div; +    M.x86.R_AH = (u8)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_word(u16 s) +{ +    u32 dvd, div, mod; + +    dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u16)s; +    mod = dvd % (u16)s; +    if (abs(div) > 0xffff) { +        x86emu_intr_raise(0); +        return; +    } +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_SF); +    CONDITIONAL_SET_FLAG(div == 0, F_ZF); +    set_parity_flag(mod); + +    M.x86.R_AX = (u16)div; +    M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    u64 dvd, div, mod; + +    dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u32)s; +    mod = dvd % (u32)s; +    if (abs(div) > 0xffffffff) { +        x86emu_intr_raise(0); +        return; +    } +#else +    s32 div = 0, mod; +    s32 h_dvd = M.x86.R_EDX; +    u32 l_dvd = M.x86.R_EAX; + +    u32 h_s = s; +    u32 l_s = 0; +    int counter = 32; +    int carry; + +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    do { +        div <<= 1; +        carry = (l_dvd >= l_s) ? 0 : 1; + +        if (h_dvd < (h_s + carry)) { +            h_s >>= 1; +            l_s = s << (--counter); +            continue; +        } else { +            h_dvd -= (h_s + carry); +            l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) +                : (l_dvd - l_s); +            h_s >>= 1; +            l_s = s << (--counter); +            div |= 1; +            continue; +        } + +    } while (counter > -1); +    /* overflow */ +    if (h_dvd || (l_dvd > s)) { +        x86emu_intr_raise(0); +        return; +    } +    mod = l_dvd; +#endif +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    CLEAR_FLAG(F_SF); +    SET_FLAG(F_ZF); +    set_parity_flag(mod); + +    M.x86.R_EAX = (u32)div; +    M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IN string instruction and side effects. +****************************************************************************/ + +static void single_in(int size) +{ +    if(size == 1) +        store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inb)(M.x86.R_DX)); +    else if (size == 2) +        store_data_word_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inw)(M.x86.R_DX)); +    else +        store_data_long_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inl)(M.x86.R_DX)); +} + +void ins(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* in until CX is ZERO. */ +        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? +                     M.x86.R_ECX : M.x86.R_CX); + +        while (count--) { +          single_in(size); +          M.x86.R_DI += inc; +          } +        M.x86.R_CX = 0; +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_ECX = 0; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        single_in(size); +        M.x86.R_DI += inc; +    } +} + +/**************************************************************************** +REMARKS: +Implements the OUT string instruction and side effects. +****************************************************************************/ + +static void single_out(int size) +{ +     if(size == 1) +       (*sys_outb)(M.x86.R_DX,fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); +     else if (size == 2) +       (*sys_outw)(M.x86.R_DX,fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); +     else +       (*sys_outl)(M.x86.R_DX,fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); +} + +void outs(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* out until CX is ZERO. */ +        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? +                     M.x86.R_ECX : M.x86.R_CX); +        while (count--) { +          single_out(size); +          M.x86.R_SI += inc; +          } +        M.x86.R_CX = 0; +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_ECX = 0; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        single_out(size); +        M.x86.R_SI += inc; +    } +} + +/**************************************************************************** +PARAMETERS: +addr    - Address to fetch word from + +REMARKS: +Fetches a word from emulator memory using an absolute address. +****************************************************************************/ +u16 mem_access_word(int addr) +{ +DB( if (CHECK_MEM_ACCESS()) +      x86emu_check_mem_access(addr);) +    return (*sys_rdw)(addr); +} + +/**************************************************************************** +REMARKS: +Pushes a word onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_word(u16 w) +{ +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    M.x86.R_SP -= 2; +    (*sys_wrw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pushes a long onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_long(u32 w) +{ +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    M.x86.R_SP -= 4; +    (*sys_wrl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pops a word from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u16 pop_word(void) +{ +    u16 res; + +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    res = (*sys_rdw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP); +    M.x86.R_SP += 2; +    return res; +} + +/**************************************************************************** +REMARKS: +Pops a long from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u32 pop_long(void) +{ +    u32 res; + +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    res = (*sys_rdl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP); +    M.x86.R_SP += 4; +    return res; +} + diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c new file mode 100644 index 000000000..bb7fcd93a --- /dev/null +++ b/drivers/bios_emulator/x86emu/sys.c @@ -0,0 +1,322 @@ +/**************************************************************************** +* +*                       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 which are related to +*               programmed I/O and memory access. Included in this module +*               are default functions that do nothing. For real uses these +*               functions will have to be overriden by the user library. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +X86EMU_sysEnv _X86EMU_env;	/* Global emulator machine state */ +X86EMU_intrFuncs _X86EMU_intrTab[256]; + +int debug_intr; + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Byte value read from emulator memory. + +REMARKS: +Reads a byte value from the emulator memory. +****************************************************************************/ +u8 X86API rdb(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Word value read from emulator memory. + +REMARKS: +Reads a word value from the emulator memory. +****************************************************************************/ +u16 X86API rdw(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Long value read from emulator memory. +REMARKS: +Reads a long value from the emulator memory. +****************************************************************************/ +u32 X86API rdl(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a byte value to emulator memory. +****************************************************************************/ +void X86API wrb(u32 addr, u8 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a word value to emulator memory. +****************************************************************************/ +void X86API wrw(u32 addr, u16 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a long value to emulator memory. +****************************************************************************/ +void X86API wrl(u32 addr, u32 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO byte read function. Doesn't perform real inb. +****************************************************************************/ +static u8 X86API p_inb(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inb %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO word read function. Doesn't perform real inw. +****************************************************************************/ +static u16 X86API p_inw(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inw %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO long read function. Doesn't perform real inl. +****************************************************************************/ +static u32 X86API p_inl(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inl %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO byte write function. Doesn't perform real outb. +****************************************************************************/ +static void X86API p_outb(X86EMU_pioAddr addr, u8 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outb %#02x -> %#04x \n", val, addr);) +		return; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO word write function. Doesn't perform real outw. +****************************************************************************/ +static void X86API p_outw(X86EMU_pioAddr addr, u16 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outw %#04x -> %#04x \n", val, addr);) +		return; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO ;ong write function. Doesn't perform real outl. +****************************************************************************/ +static void X86API p_outl(X86EMU_pioAddr addr, u32 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outl %#08x -> %#04x \n", val, addr);) +		return; +} + +/*------------------------- Global Variables ------------------------------*/ + +u8(X86APIP sys_rdb) (u32 addr) = rdb; +u16(X86APIP sys_rdw) (u32 addr) = rdw; +u32(X86APIP sys_rdl) (u32 addr) = rdl; +void (X86APIP sys_wrb) (u32 addr, u8 val) = wrb; +void (X86APIP sys_wrw) (u32 addr, u16 val) = wrw; +void (X86APIP sys_wrl) (u32 addr, u32 val) = wrl; +u8(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb; +u16(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw; +u32(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl; +void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val) = p_outb; +void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val) = p_outw; +void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val) = p_outl; + +/*----------------------------- Setup -------------------------------------*/ + +/**************************************************************************** +PARAMETERS: +funcs   - New memory function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +memory space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs) +{ +	sys_rdb = funcs->rdb; +	sys_rdw = funcs->rdw; +	sys_rdl = funcs->rdl; +	sys_wrb = funcs->wrb; +	sys_wrw = funcs->wrw; +	sys_wrl = funcs->wrl; +} + +/**************************************************************************** +PARAMETERS: +funcs   - New programmed I/O function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +I/O space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs) +{ +	sys_inb = funcs->inb; +	sys_inw = funcs->inw; +	sys_inl = funcs->inl; +	sys_outb = funcs->outb; +	sys_outw = funcs->outw; +	sys_outl = funcs->outl; +} + +/**************************************************************************** +PARAMETERS: +funcs   - New interrupt vector table to make active + +REMARKS: +This function is used to set the pointers to functions which handle +interrupt processing in the emulator, allowing the user application to +hook interrupts as necessary for their application. Any interrupts that +are not hooked by the user application, and reflected and handled internally +in the emulator via the interrupt vector table. This allows the application +to get control when the code being emulated executes specific software +interrupts. +****************************************************************************/ +void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]) +{ +	int i; + +	for (i = 0; i < 256; i++) +		_X86EMU_intrTab[i] = NULL; +	if (funcs) { +		for (i = 0; i < 256; i++) +			_X86EMU_intrTab[i] = funcs[i]; +	} +} + +/**************************************************************************** +PARAMETERS: +int - New software interrupt to prepare for + +REMARKS: +This function is used to set up the emulator state to exceute a software +interrupt. This can be used by the user application code to allow an +interrupt to be hooked, examined and then reflected back to the emulator +so that the code in the emulator will continue processing the software +interrupt as per normal. This essentially allows system code to actively +hook and handle certain software interrupts as necessary. +****************************************************************************/ +void X86EMU_prepareForInt(int num) +{ +	push_word((u16) M.x86.R_FLG); +	CLEAR_FLAG(F_IF); +	CLEAR_FLAG(F_TF); +	push_word(M.x86.R_CS); +	M.x86.R_CS = mem_access_word(num * 4 + 2); +	push_word(M.x86.R_IP); +	M.x86.R_IP = mem_access_word(num * 4); +	M.x86.intr = 0; +} |