diff --git a/BaS_gcc/Makefile b/BaS_gcc/Makefile index 2e103b9..d9b672c 100644 --- a/BaS_gcc/Makefile +++ b/BaS_gcc/Makefile @@ -120,6 +120,10 @@ CSRCS= \ decode.c \ sys.c \ debug.c \ + prim_ops.c \ + ops.c \ + ops2.c \ + x86pcibios.c \ \ basflash.c \ basflash_start.c diff --git a/BaS_gcc/bas.lk.in b/BaS_gcc/bas.lk.in index 7a25993..3bf289d 100644 --- a/BaS_gcc/bas.lk.in +++ b/BaS_gcc/bas.lk.in @@ -88,8 +88,12 @@ SECTIONS OBJDIR/biosemu.o OBJDIR/decode.o + OBJDIR/ops.o + OBJDIR/ops2.o OBJDIR/sys.o OBJDIR/debug.o + OBJDIR/prim_ops.o + OBJDIR/x86pcibios.o OBJDIR/radeon_base.o OBJDIR/radeon_accel.o diff --git a/BaS_gcc/include/x86pcibios.h b/BaS_gcc/include/x86pcibios.h new file mode 100644 index 0000000..5445c73 --- /dev/null +++ b/BaS_gcc/include/x86pcibios.h @@ -0,0 +1,29 @@ +#ifndef PCI_BIOS_H +#define PCI_BIOS_H + +enum { + PCI_BIOS_PRESENT = 0xB101, + FIND_PCI_DEVICE = 0xB102, + FIND_PCI_CLASS_CODE = 0xB103, + GENERATE_SPECIAL_CYCLE = 0xB106, + READ_CONFIG_BYTE = 0xB108, + READ_CONFIG_WORD = 0xB109, + READ_CONFIG_DWORD = 0xB10A, + WRITE_CONFIG_BYTE = 0xB10B, + WRITE_CONFIG_WORD = 0xB10C, + WRITE_CONFIG_DWORD = 0xB10D, + GET_IRQ_ROUTING_OPTIONS = 0xB10E, + SET_PCI_IRQ = 0xB10F +}; + +enum { + SUCCESSFUL = 0x00, + FUNC_NOT_SUPPORTED = 0x81, + BAD_VENDOR_ID = 0x83, + DEVICE_NOT_FOUND = 0x86, + BAD_REGISTER_NUMBER = 0x87, + SET_FAILED = 0x88, + BUFFER_TOO_SMALL = 0x89 +}; +#endif /* PCI_BIOS_H */ + diff --git a/BaS_gcc/sys/init_fpga.c b/BaS_gcc/sys/init_fpga.c index 55ff3fa..2e9254b 100644 --- a/BaS_gcc/sys/init_fpga.c +++ b/BaS_gcc/sys/init_fpga.c @@ -39,6 +39,7 @@ extern uint8_t _FPGA_FLASH_DATA_SIZE[]; #define FPGA_FLASH_DATA_SIZE ((uint32_t) &_FPGA_FLASH_DATA_SIZE[0]) +#ifdef _NOT_USED_ void test_longword(void) { uint32_t *fpga_data = (uint32_t *) FPGA_FLASH_DATA; @@ -76,6 +77,7 @@ void test_byte(void) } while (fpga_data < fpga_flash_data_end); xprintf("finished. \r\n"); } +#endif /* _NOT_USED_ */ /* * load FPGA diff --git a/BaS_gcc/x86emu/biosemu.c b/BaS_gcc/x86emu/biosemu.c index 5c8d6f1..20d4183 100644 --- a/BaS_gcc/x86emu/biosemu.c +++ b/BaS_gcc/x86emu/biosemu.c @@ -68,7 +68,7 @@ uint32_t offset_mem; static uint32_t offset_io; static uint32_t config_address_reg; -extern int pcibios_handler(); +extern int x86_pcibios_emulator(); extern COOKIE *get_cookie(long id); extern short restart, os_magic; @@ -232,7 +232,7 @@ void do_int(int num) ret = 0; break; case 0x1A: - ret = pcibios_handler(); + ret = x86_pcibios_emulator(); ret = 1; break; case 0xe6: diff --git a/BaS_gcc/x86emu/debug.c b/BaS_gcc/x86emu/debug.c new file mode 100644 index 0000000..f13c49b --- /dev/null +++ b/BaS_gcc/x86emu/debug.c @@ -0,0 +1,477 @@ +/**************************************************************************** +* +* 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 "bas_types.h" +#include "bas_printf.h" +#include "x86debug.h" +#include "x86emui.h" + +/*----------------------------- Implementation ----------------------------*/ + +#ifdef DBG_X86EMU + +static void print_encoded_bytes (uint16_t s, uint16_t 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()) { + dbg("0x%x", M.x86.saved_cs); + dbg(":0x%x", M.x86.saved_ip); + dbg(" "); + 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! + */ + dbg("%x:%x ", M.x86.saved_cs, M.x86.saved_ip); + print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip); + print_decoded_instruction(); +} + +#if 0 +static void disassemble_forward (uint16_t seg, uint16_t 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 256) return; + seg = fetch_data_word_abs(0,iv*4); + off = fetch_data_word_abs(0,iv*4+2); + dbg("%x:%x", seg, off); + dbg(" "); +} + +void X86EMU_dump_memory (uint16_t seg, uint16_t off, uint32_t amt) +{ + uint32_t start = off & 0xfffffff0; + uint32_t end = (off+16) & 0xfffffff0; + uint32_t i; + uint32_t current; + + current = start; + while (end <= off + amt) { + dbg("%x:%x: ", seg, start); + dbg(" "); + for (i = start; i < off; i++) + dbg(" "); + for ( ; i< end; i++) + dbg(" %x\r\n", fetch_data_byte_abs(seg,i)); + start = end; + end = start + 16; + } +} + +void x86emu_single_step (void) +{ +#if 0 + 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) { + DPRINT("-"); + p = fgets(s, 1023, stdin); + cmd = parse_line(s, ps, &ntok); + switch(cmd) { + case 'u': + disassemble_forward(M.x86.saved_cs,(uint16_t)offset,10); + break; + case 'd': + if (ntok == 2) { + segment = M.x86.saved_cs; + offset = ps[1]; + X86EMU_dump_memory(segment,(uint16_t)offset,16); + offset += 16; + } else if (ntok == 3) { + segment = ps[1]; + offset = ps[2]; + X86EMU_dump_memory(segment,(uint16_t)offset,16); + offset += 16; + } else { + segment = M.x86.saved_cs; + X86EMU_dump_memory(segment,(uint16_t)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; + DPRINT("Toggled decoding to "); + DPRINT((noDecode)?"FALSE":"TRUE"); + DPRINT("\r\n"); + break; + case 't': + case 0: + done = 1; + break; + } + } +#endif +} + +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); +} + +int X86EMU_set_debug(int debug) +{ + return M.x86.debug = debug; +} + +#if 0 +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++; + + sscanf(s,"%x",&ps[*n]); + *n += 1; + } +} +#endif + +#endif /* DEBUG */ + +void x86emu_dump_regs (void) +{ + dbg(" AX=%x", M.x86.R_AX ); + dbg(" BX=%x", M.x86.R_BX ); + dbg(" CX=%x", M.x86.R_CX ); + dbg(" DX=%x", M.x86.R_DX ); + dbg(" SP=%x", M.x86.R_SP ); + dbg(" BP=%x", M.x86.R_BP ); + dbg(" SI=%x", M.x86.R_SI ); + dbg(" DI=%x", M.x86.R_DI ); + dbg("\r\n"); + dbg(" DS=%x", M.x86.R_DS ); + dbg(" ES=%x", M.x86.R_ES ); + dbg(" SS=%x", M.x86.R_SS ); + dbg(" CS=%x", M.x86.R_CS ); + dbg(" IP=%x", M.x86.R_IP ); + dbg("\r\n "); + if (ACCESS_FLAG(F_OF)) dbg("OV "); /* CHECKED... */ + else dbg("NV "); + if (ACCESS_FLAG(F_DF)) dbg("DN "); + else dbg("UP "); + if (ACCESS_FLAG(F_IF)) dbg("EI "); + else dbg("DI "); + if (ACCESS_FLAG(F_SF)) dbg("NG "); + else dbg("PL "); + if (ACCESS_FLAG(F_ZF)) dbg("ZR "); + else dbg("NZ "); + if (ACCESS_FLAG(F_AF)) dbg("AC "); + else dbg("NA "); + if (ACCESS_FLAG(F_PF)) dbg("PE "); + else dbg("PO "); + if (ACCESS_FLAG(F_CF)) dbg("CY "); + else dbg("NC "); + dbg("\r\n"); +} + +void x86emu_dump_xregs (void) +{ + dbg(" EAX=%x", M.x86.R_EAX ); + dbg(" EBX=%x", M.x86.R_EBX ); + dbg(" ECX=%x", M.x86.R_ECX ); + dbg(" EDX=%x", M.x86.R_EDX ); + dbg("\r\n"); + dbg(" ESP=%x", M.x86.R_ESP ); + dbg(" EBP=%x", M.x86.R_EBP ); + dbg(" ESI=%x", M.x86.R_ESI ); + dbg(" EDI=%x", M.x86.R_EDI ); + dbg("\r\n"); + dbg(" DS=%x", M.x86.R_DS ); + dbg(" ES=%x", M.x86.R_ES ); + dbg(" SS=%x", M.x86.R_SS ); + dbg(" CS=%x", M.x86.R_CS ); + dbg(" EIP%x=", M.x86.R_EIP ); + dbg("\r\n "); + if (ACCESS_FLAG(F_OF)) dbg("OV "); /* CHECKED... */ + else dbg("NV "); + if (ACCESS_FLAG(F_DF)) dbg("DN "); + else dbg("UP "); + if (ACCESS_FLAG(F_IF)) dbg("EI "); + else dbg("DI "); + if (ACCESS_FLAG(F_SF)) dbg("NG "); + else dbg("PL "); + if (ACCESS_FLAG(F_ZF)) dbg("ZR "); + else dbg("NZ "); + if (ACCESS_FLAG(F_AF)) dbg("AC "); + else dbg("NA "); + if (ACCESS_FLAG(F_PF)) dbg("PE "); + else dbg("PO "); + if (ACCESS_FLAG(F_CF)) dbg("CY "); + else dbg("NC "); + dbg("\r\n"); +} diff --git a/BaS_gcc/x86emu/decode.c b/BaS_gcc/x86emu/decode.c new file mode 100644 index 0000000..34d1e3d --- /dev/null +++ b/BaS_gcc/x86emu/decode.c @@ -0,0 +1,1151 @@ +/**************************************************************************** +* +* 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 "x86emui.h" +#include +#include "bas_printf.h" +#include "x86debug.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +REMARKS: +Handles any pending asychronous interrupts. +****************************************************************************/ +static void x86emu_intr_handle(void) +{ + uint8_t intno; + + if (M.x86.intr & INTR_SYNCH) { + intno = M.x86.intno; + if (_X86EMU_intrTab[intno]) { + (*_X86EMU_intrTab[intno])(intno); + } else { + push_word((uint16_t)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(uint8_t intrnum) +{ + dbg("Rasing exception 0x%02x\r\n", intrnum); + x86emu_dump_regs(); + 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) +{ + uint8_t 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) { + DPRINT("halted\r\n"); + X86EMU_trace_regs(); + } + else { + if (M.x86.debug) + DPRINT("Service completed successfully\r\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)(((uint32_t)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)(((uint32_t)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! +****************************************************************************/ +uint8_t fetch_byte_imm(void) +{ + uint8_t fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdb)(((uint32_t)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! +****************************************************************************/ +uint16_t fetch_word_imm(void) +{ + uint16_t fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdw)(((uint32_t)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! +****************************************************************************/ +uint32_t fetch_long_imm(void) +{ + uint32_t fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdl)(((uint32_t)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 uint32_t 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 + DPRINT("error: should not happen: multiple overrides.\r\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! +****************************************************************************/ +uint8_t fetch_data_byte( + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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! +****************************************************************************/ +uint16_t fetch_data_word( + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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! +****************************************************************************/ +uint32_t fetch_data_long( + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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! +****************************************************************************/ +uint8_t fetch_data_byte_abs( + unsigned int segment, + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdb)(((uint32_t)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to load data from +offset - Offset to load data from + +RETURNS: +Word value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +uint16_t fetch_data_word_abs( + unsigned int segment, + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdw)(((uint32_t)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to load data from +offset - Offset to load data from + +RETURNS: +Long value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +uint32_t fetch_data_long_abs( + unsigned int segment, + unsigned int offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdl)(((uint32_t)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a word value to an segmented memory location. The segment used is +the current 'default' segment, which may have been overridden. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_byte( + unsigned int offset, + uint8_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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( + unsigned int offset, + uint16_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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( + unsigned int offset, + uint32_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((uint16_t)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( + unsigned int segment, + unsigned int offset, + uint8_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrb)(((uint32_t)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to store data at +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a word value to an absolute memory location. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_word_abs( + unsigned int segment, + unsigned int offset, + uint16_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrw)(((uint32_t)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to store data at +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a long value to an absolute memory location. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_long_abs( + unsigned int segment, + unsigned int offset, + uint32_t val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrl)(((uint32_t)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +reg - Register to decode + +RETURNS: +Pointer to the appropriate register + +REMARKS: +Return a pointer to the register given by the R/RM field of the +modrm byte, for byte operands. Also enables the decoding of instructions. +****************************************************************************/ +uint8_t* 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. +****************************************************************************/ +uint16_t* 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. +****************************************************************************/ +uint32_t* 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. +****************************************************************************/ +uint16_t* 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 = (int32_t)fetch_long_imm(); + DECODE_PRINTF2("[%d]", displacement); + offset = displacement; + break; + case 1: + displacement = (int8_t)fetch_byte_imm(); + DECODE_PRINTF2("[%d][EBP]", displacement); + offset = M.x86.R_EBP + displacement; + break; + case 2: + displacement = (int32_t)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("[%x]", 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("[%x]", 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 = (int8_t)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 = (int8_t)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 = (int8_t)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 = (int32_t)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 = (int32_t)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 = (int16_t)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/BaS_gcc/x86emu/ops.c b/BaS_gcc/x86emu/ops.c new file mode 100644 index 0000000..b2d8656 --- /dev/null +++ b/BaS_gcc/x86emu/ops.c @@ -0,0 +1,5418 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1991-2004 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file includes subroutines to implement the decoding +* and emulation of all the x86 processor instructions. +* +* There are approximately 250 subroutines in here, which correspond +* to the 256 byte-"opcodes" found on the 8086. The table which +* dispatches this is found in the files optab.[ch]. +* +* Each opcode proc has a comment 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. +* +****************************************************************************/ + +#include "x86debug.h" +#include "x86emui.h" + +extern unsigned decode_rmXX_address(int mod, int rm); + +/*----------------------------- 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 uint8_t (*genop_byte_operation[])(uint8_t d, uint8_t s) = +{ + add_byte, /* 00 */ + or_byte, /* 01 */ + adc_byte, /* 02 */ + sbb_byte, /* 03 */ + and_byte, /* 04 */ + sub_byte, /* 05 */ + xor_byte, /* 06 */ + cmp_byte, /* 07 */ +}; + +static uint16_t (*genop_word_operation[])(uint16_t d, uint16_t s) = +{ + add_word, /*00 */ + or_word, /*01 */ + adc_word, /*02 */ + sbb_word, /*03 */ + and_word, /*04 */ + sub_word, /*05 */ + xor_word, /*06 */ + cmp_word, /*07 */ +}; + +static uint32_t (*genop_long_operation[])(uint32_t d, uint32_t s) = +{ + add_long, /*00 */ + or_long, /*01 */ + adc_long, /*02 */ + sbb_long, /*03 */ + and_long, /*04 */ + sub_long, /*05 */ + xor_long, /*06 */ + cmp_long, /*07 */ +}; + +/* used by opcodes 80, c0, d0, and d2. */ +static uint8_t(*opcD0_byte_operation[])(uint8_t d, uint8_t s) = +{ + rol_byte, + ror_byte, + rcl_byte, + rcr_byte, + shl_byte, + shr_byte, + shl_byte, /* sal_byte === shl_byte by definition */ + sar_byte, +}; + +/* used by opcodes c1, d1, and d3. */ +static uint16_t(*opcD1_word_operation[])(uint16_t s, uint8_t d) = +{ + rol_word, + ror_word, + rcl_word, + rcr_word, + shl_word, + shr_word, + shl_word, /* sal_byte === shl_byte by definition */ + sar_word, +}; + +/* used by opcodes c1, d1, and d3. */ +static uint32_t (*opcD1_long_operation[])(uint32_t s, uint8_t d) = +{ + rol_long, + ror_long, + rcl_long, + rcr_long, + shl_long, + shr_long, + shl_long, /* sal_byte === shl_byte by definition */ + sar_long, +}; + +#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( + uint8_t op1) +{ + START_OF_INSTR(); + if (M.x86.R_SP != 0) { + DECODE_PRINTF("ILLEGAL X86 OPCODE\r\n"); + TRACE_REGS(); + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP-1); + DPRINTVALHEXBYTE(": ", op1); + DPRINT(" ILLEGAL X86 OPCODE!\r\n"); + 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(uint8_t op1) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t *destreg, *srcreg; + uint8_t 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("\r\n"); + TRACE_AND_STEP(); + destval = genop_byte_operation[op1](destval, *srcreg); + if (op1 != 7) + store_data_byte(destoffset, destval); + } + else + { /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\r\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(uint8_t op1) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval; + uint32_t *srcreg; + + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = genop_long_operation[op1](destval, *srcreg); + if (op1 != 7) + store_data_long(destoffset, destval); + } else { + uint16_t destval; + uint16_t *srcreg; + + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = genop_word_operation[op1](destval, *srcreg); + if (op1 != 7) + store_data_word(destoffset, destval); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg, *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = genop_long_operation[op1](*destreg, *srcreg); + } else { + uint16_t *destreg, *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\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(uint8_t op1) +{ + int mod, rl, rh; + uint8_t *destreg, *srcreg; + unsigned int srcoffset; + uint8_t 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("\r\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(uint8_t op1) +{ + int mod, rl, rh; + unsigned int srcoffset; + uint32_t *destreg32, srcval; + uint16_t *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("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = genop_word_operation[op1](*destreg, srcval); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *srcreg; + destreg32 = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg32 = genop_long_operation[op1](*destreg32, *srcreg); + } else { + uint16_t *srcreg; + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\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(uint8_t op1) +{ + uint8_t srcval; + + op1 = (op1 >> 3) & 0x7; + + START_OF_INSTR(); + DECODE_PRINTF(x86emu_GenOpName[op1]); + DECODE_PRINTF("\tAL,"); + srcval = fetch_byte_imm(); + DECODE_PRINTF2("%x\r\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(uint8_t op1) +{ + uint32_t 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\r\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, (uint16_t)srcval); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x06 +****************************************************************************/ +void x86emuOp_push_ES(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tES\r\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_ES); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x07 +****************************************************************************/ +void x86emuOp_pop_ES(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tES\r\n"); + TRACE_AND_STEP(); + M.x86.R_ES = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0e +****************************************************************************/ +void x86emuOp_push_CS(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tCS\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t op2 = (*sys_rdb)(((uint32_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tSS\r\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_SS); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x17 +****************************************************************************/ +void x86emuOp_pop_SS(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tSS\r\n"); + TRACE_AND_STEP(); + M.x86.R_SS = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x1e +****************************************************************************/ +void x86emuOp_push_DS(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tDS\r\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_DS); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x1f +****************************************************************************/ +void x86emuOp_pop_DS(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tDS\r\n"); + TRACE_AND_STEP(); + M.x86.R_DS = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x26 +****************************************************************************/ +void x86emuOp_segovr_ES(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("ES:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("DAA\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("CS:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("DAS\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("SS:\r\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_SEGOVR_SS; + /* no DECODE_CLEAR_SEGOVR ! */ + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x37 +****************************************************************************/ +void x86emuOp_aaa(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("AAA\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("DS:\r\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_SEGOVR_DS; + /* NO DECODE_CLEAR_SEGOVR! */ + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x3f +****************************************************************************/ +void x86emuOp_aas(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("AAS\r\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(uint8_t op1) +{ + START_OF_INSTR(); + op1 &= 0x7; + DECODE_PRINTF("INC\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg; + reg = DECODE_RM_LONG_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = inc_long(*reg); + } else { + uint16_t *reg; + reg = DECODE_RM_WORD_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = inc_word(*reg); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x48 - 0x4F +****************************************************************************/ +void x86emuOp_dec_register(uint8_t op1) +{ + START_OF_INSTR(); + op1 &= 0x7; + DECODE_PRINTF("DEC\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg; + reg = DECODE_RM_LONG_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = dec_long(*reg); + } else { + uint16_t *reg; + reg = DECODE_RM_WORD_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = dec_word(*reg); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x50 - 0x57 +****************************************************************************/ +void x86emuOp_push_register(uint8_t op1) +{ + START_OF_INSTR(); + op1 &= 0x7; + DECODE_PRINTF("PUSH\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg; + reg = DECODE_RM_LONG_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + push_long(*reg); + } else { + uint16_t *reg; + reg = DECODE_RM_WORD_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + push_word(*reg); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x58 - 0x5F +****************************************************************************/ +void x86emuOp_pop_register(uint8_t op1) +{ + START_OF_INSTR(); + op1 &= 0x7; + DECODE_PRINTF("POP\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg; + reg = DECODE_RM_LONG_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = pop_long(); + } else { + uint16_t *reg; + reg = DECODE_RM_WORD_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *reg = pop_word(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x60 +****************************************************************************/ +void x86emuOp_push_all(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("PUSHAD\r\n"); + } else { + DECODE_PRINTF("PUSHA\r\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t 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 { + uint16_t 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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("POPAD\r\n"); + } else { + DECODE_PRINTF("POPA\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("FS:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("GS:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("DATA:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("ADDR:\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t 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\r\n", imm); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + push_long(imm); + } else { + push_word((uint16_t)imm); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x69 +****************************************************************************/ +void x86emuOp_imul_word_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t *destreg; + uint32_t srcval; + uint32_t res_lo,res_hi; + int32_t imm; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcval = fetch_data_long(srcoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(int32_t)srcval,(int32_t)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 = (uint32_t)res_lo; + } else { + uint16_t *destreg; + uint16_t srcval; + uint32_t res; + int16_t imm; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcval = fetch_data_word(srcoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + res = (int16_t)srcval * (int16_t)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 = (uint16_t)res; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg,*srcreg; + uint32_t res_lo,res_hi; + int32_t imm; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(int32_t)*srcreg,(int32_t)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 = (uint32_t)res_lo; + } else { + uint16_t *destreg,*srcreg; + uint32_t res; + int16_t imm; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + res = (int16_t)*srcreg * (int16_t)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 = (uint16_t)res; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6a +****************************************************************************/ +void x86emuOp_push_byte_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int16_t imm; + + START_OF_INSTR(); + imm = (int8_t)fetch_byte_imm(); + DECODE_PRINTF2("PUSH\t%d\r\n", imm); + TRACE_AND_STEP(); + push_word(imm); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6b +****************************************************************************/ +void x86emuOp_imul_byte_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int srcoffset; + int8_t 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) { + uint32_t *destreg; + uint32_t srcval; + uint32_t res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcval = fetch_data_long(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(int32_t)srcval,(int32_t)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 = (uint32_t)res_lo; + } else { + uint16_t *destreg; + uint16_t srcval; + uint32_t res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcval = fetch_data_word(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + res = (int16_t)srcval * (int16_t)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 = (uint16_t)res; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg,*srcreg; + uint32_t 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\r\n", (int32_t)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(int32_t)*srcreg,(int32_t)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 = (uint32_t)res_lo; + } else { + uint16_t *destreg,*srcreg; + uint32_t res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\n", (int32_t)imm); + TRACE_AND_STEP(); + res = (int16_t)*srcreg * (int16_t)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 = (uint16_t)res; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6c +****************************************************************************/ +void x86emuOp_ins_byte(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("INSB\r\n"); + ins(1); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6d +****************************************************************************/ +void x86emuOp_ins_word(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("INSD\r\n"); + ins(4); + } else { + DECODE_PRINTF("INSW\r\n"); + ins(2); + } + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6e +****************************************************************************/ +void x86emuOp_outs_byte(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("OUTSB\r\n"); + outs(1); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6f +****************************************************************************/ +void x86emuOp_outs_word(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("OUTSD\r\n"); + outs(4); + } else { + DECODE_PRINTF("OUTSW\r\n"); + outs(2); + } + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x70 - 0x7F +****************************************************************************/ +int x86emu_check_jump_condition(uint8_t op); + +void x86emuOp_jump_near_cond(uint8_t op1) +{ + int8_t offset; + uint16_t target; + int cond; + + /* jump to byte offset if overflow flag is set */ + START_OF_INSTR(); + cond = x86emu_check_jump_condition(op1 & 0xF); + offset = (int8_t)fetch_byte_imm(); + target = (uint16_t)(M.x86.R_IP + (int16_t)offset); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t imm; + uint8_t 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\r\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\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_byte_operation[rh]) (*destreg, imm); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x81 +****************************************************************************/ +void x86emuOp_opc81_word_RM_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval,imm; + + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\r\n", imm); + TRACE_AND_STEP(); + destval = (*genop_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + uint16_t destval,imm; + + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\r\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) { + uint32_t *destreg, imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_long_operation[rh]) (*destreg, imm); + } else { + uint16_t *destreg, imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_word_operation[rh]) (*destreg, imm); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x82 +****************************************************************************/ +void x86emuOp_opc82_byte_RM_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t imm; + uint8_t 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\r\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\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_byte_operation[rh]) (*destreg, imm); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x83 +****************************************************************************/ +void x86emuOp_opc83_word_RM_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval,imm; + + destval = fetch_data_long(destoffset); + imm = (int8_t) fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + destval = (*genop_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + uint16_t destval,imm; + + destval = fetch_data_word(destoffset); + imm = (int8_t) fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\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) { + uint32_t *destreg, imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + imm = (int8_t) fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_long_operation[rh]) (*destreg, imm); + } else { + uint16_t *destreg, imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + imm = (int8_t) fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = (*genop_word_operation[rh]) (*destreg, imm); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x84 +****************************************************************************/ +void x86emuOp_test_byte_RM_R(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg, *srcreg; + unsigned int destoffset; + uint8_t 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("\r\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("\r\n"); + TRACE_AND_STEP(); + test_byte(*destreg, *srcreg); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x85 +****************************************************************************/ +void x86emuOp_test_word_RM_R(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval; + uint32_t *srcreg; + + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + test_long(destval, *srcreg); + } else { + uint16_t destval; + uint16_t *srcreg; + + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + test_word(destval, *srcreg); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg,*srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + test_long(*destreg, *srcreg); + } else { + uint16_t *destreg,*srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + test_word(*destreg, *srcreg); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x86 +****************************************************************************/ +void x86emuOp_xchg_byte_RM_R(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg, *srcreg; + unsigned int destoffset; + uint8_t destval; + uint8_t 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("\r\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("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t *srcreg; + uint32_t destval,tmp; + + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_long(destoffset, destval); + } else { + uint16_t *srcreg; + uint16_t destval,tmp; + + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\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) { + uint32_t *destreg,*srcreg; + uint32_t tmp; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + } else { + uint16_t *destreg,*srcreg; + uint16_t tmp; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg, *srcreg; + unsigned int 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("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x89 +****************************************************************************/ +void x86emuOp_mov_word_RM_R(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t *srcreg; + + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + store_data_long(destoffset, *srcreg); + } else { + uint16_t *srcreg; + + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + store_data_word(destoffset, *srcreg); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg,*srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + uint16_t *destreg,*srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8a +****************************************************************************/ +void x86emuOp_mov_byte_R_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg, *srcreg; + unsigned int srcoffset; + uint8_t 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("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8b +****************************************************************************/ +void x86emuOp_mov_word_R_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (mod < 3) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = fetch_data_long(srcoffset); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + uint16_t *destreg; + uint16_t srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg, *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + uint16_t *destreg, *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8c +****************************************************************************/ +void x86emuOp_mov_word_RM_SR(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint16_t *destreg, *srcreg; + unsigned int destoffset; + uint16_t 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("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8d +****************************************************************************/ +void x86emuOp_lea_word_R_M(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint16_t *srcreg; + unsigned int 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("\r\n"); + TRACE_AND_STEP(); + *srcreg = (uint16_t)destoffset; + } + /* } else { undefined. Do nothing. } */ + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8e +****************************************************************************/ +void x86emuOp_mov_word_SR_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint16_t *destreg, *srcreg; + unsigned int srcoffset; + uint16_t 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("\r\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("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("POP\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\r\n"); + HALT_SYS(); + } + if (mod < 3) { + destoffset = decode_rmXX_address(mod, rl); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t destval; + + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = pop_long(); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = pop_word(); + store_data_word(destoffset, destval); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = pop_long(); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = pop_word(); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x90 +****************************************************************************/ +void x86emuOp_nop(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("NOP\r\n"); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x91-0x97 +****************************************************************************/ +void x86emuOp_xchg_word_AX_register(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t tmp; + + op1 &= 0x7; + + START_OF_INSTR(); + + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg32; + DECODE_PRINTF("XCHG\tEAX,"); + reg32 = DECODE_RM_LONG_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + tmp = M.x86.R_EAX; + M.x86.R_EAX = *reg32; + *reg32 = tmp; + } else { + uint16_t *reg16; + DECODE_PRINTF("XCHG\tAX,"); + reg16 = DECODE_RM_WORD_REGISTER(op1); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + tmp = M.x86.R_AX; + M.x86.R_AX = *reg16; + *reg16 = (uint16_t)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x98 +****************************************************************************/ +void x86emuOp_cbw(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CWDE\r\n"); + } else { + DECODE_PRINTF("CBW\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CDQ\r\n"); + } else { + DECODE_PRINTF("CWD\r\n"); + } + DECODE_PRINTF("CWD\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t farseg, faroff; + + START_OF_INSTR(); + DECODE_PRINTF("CALL\t"); + faroff = fetch_word_imm(); + farseg = fetch_word_imm(); + DECODE_PRINTF2("%x:", farseg); + DECODE_PRINTF2("%x\r\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(uint8_t 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(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t flags; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("PUSHFD\r\n"); + } else { + DECODE_PRINTF("PUSHF\r\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((uint16_t)flags); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9d +****************************************************************************/ +void x86emuOp_popf_word(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("POPFD\r\n"); + } else { + DECODE_PRINTF("POPF\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("SAHF\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LAHF\r\n"); + TRACE_AND_STEP(); + M.x86.R_AH = (uint8_t)(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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t offset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tAL,"); + offset = fetch_word_imm(); + DECODE_PRINTF2("[%x]\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t offset; + + START_OF_INSTR(); + offset = fetch_word_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("MOV\tEAX,[%x]\r\n", offset); + } else { + DECODE_PRINTF2("MOV\tAX,[%x]\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t offset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + offset = fetch_word_imm(); + DECODE_PRINTF2("[%x],AL\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t offset; + + START_OF_INSTR(); + offset = fetch_word_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("MOV\t[%x],EAX\r\n", offset); + } else { + DECODE_PRINTF2("MOV\t[%x],AX\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t val; + uint32_t count; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("MOVS\tBYTE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t val; + int inc; + uint32_t count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOVS\tDWORD\r\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("MOVS\tWORD\r\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, (uint16_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + int8_t val1, val2; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("CMPS\tBYTE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t val1,val2; + int inc; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CMPS\tDWORD\r\n"); + inc = 4; + } else { + DECODE_PRINTF("CMPS\tWORD\r\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((uint16_t)val1, (uint16_t)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((uint16_t)val1, (uint16_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + int imm; + + START_OF_INSTR(); + DECODE_PRINTF("TEST\tAL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\r\n", imm); + TRACE_AND_STEP(); + test_byte(M.x86.R_AL, (uint8_t)imm); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa9 +****************************************************************************/ +void x86emuOp_test_AX_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t 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\r\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, (uint16_t)srcval); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaa +****************************************************************************/ +void x86emuOp_stos_byte(uint8_t X86EMU_UNUSED(op1)) +{ + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("STOS\tBYTE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int inc; + uint32_t count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("STOS\tDWORD\r\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("STOS\tWORD\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("LODS\tBYTE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int inc; + uint32_t count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("LODS\tDWORD\r\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("LODS\tWORD\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int8_t val2; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("SCAS\tBYTE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int inc; + uint32_t val; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("SCAS\tDWORD\r\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("SCAS\tWORD\r\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, (uint16_t)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, (uint16_t)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, (uint16_t)val); + } + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb0 - 0xb7 +****************************************************************************/ +void x86emuOp_mov_byte_register_IMM(uint8_t op1) +{ + uint8_t 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\r\n", imm); + TRACE_AND_STEP(); + *ptr = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb8 - 0xbf +****************************************************************************/ +void x86emuOp_mov_word_register_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + uint32_t srcval; + + op1 &= 0x7; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *reg32; + reg32 = DECODE_RM_LONG_REGISTER(op1); + srcval = fetch_long_imm(); + DECODE_PRINTF2(",%x\r\n", srcval); + TRACE_AND_STEP(); + *reg32 = srcval; + } else { + uint16_t *reg16; + reg16 = DECODE_RM_WORD_REGISTER(op1); + srcval = fetch_word_imm(); + DECODE_PRINTF2(",%x\r\n", srcval); + TRACE_AND_STEP(); + *reg16 = (uint16_t)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc0 +****************************************************************************/ +void x86emuOp_opcC0_byte_RM_MEM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t destval; + uint8_t amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + 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\r\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\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + 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) { + uint32_t destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\n", amt); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\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) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\n", amt); + TRACE_AND_STEP(); + *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t imm; + + START_OF_INSTR(); + DECODE_PRINTF("RET\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("RET\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + uint16_t *dstreg; + unsigned int 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("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + uint16_t *dstreg; + unsigned int 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("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\r\n"); + HALT_SYS(); + } + if (mod < 3) { + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rmXX_address(mod, rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%x\r\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(",%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc7 +****************************************************************************/ +void x86emuOp_mov_word_RM_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\r\n"); + HALT_SYS(); + } + if (mod < 3) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + store_data_long(destoffset, imm); + } else { + uint16_t imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + store_data_word(destoffset, imm); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + } else { + uint16_t *destreg; + uint16_t imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\r\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc8 +****************************************************************************/ +void x86emuOp_enter(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t local,frame_pointer; + uint8_t nesting; + int i; + + START_OF_INSTR(); + local = fetch_word_imm(); + nesting = fetch_byte_imm(); + DECODE_PRINTF2("ENTER %x\r\n", local); + DECODE_PRINTF2(",%x\r\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 = (uint16_t)(M.x86.R_SP - local); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc9 +****************************************************************************/ +void x86emuOp_leave(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LEAVE\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t imm; + + START_OF_INSTR(); + DECODE_PRINTF("RETF\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("RETF\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t tmp; + + START_OF_INSTR(); + DECODE_PRINTF("INT 3\r\n"); + tmp = (uint16_t) mem_access_word(3 * 4 + 2); + /* access the segment register */ + TRACE_AND_STEP(); + if (_X86EMU_intrTab[3]) { + (*_X86EMU_intrTab[3])(3); + } else { + push_word((uint16_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t tmp; + uint8_t intnum; + + START_OF_INSTR(); + DECODE_PRINTF("INT\t"); + intnum = fetch_byte_imm(); + DECODE_PRINTF2("%x\r\n", intnum); + tmp = mem_access_word(intnum * 4 + 2); + TRACE_AND_STEP(); + if (_X86EMU_intrTab[intnum]) { + (*_X86EMU_intrTab[intnum])(intnum); + } else { + push_word((uint16_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t tmp; + + START_OF_INSTR(); + DECODE_PRINTF("INTO\r\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((uint16_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("IRET\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t 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\r\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\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + DECODE_PRINTF(",1\r\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, 1); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + DECODE_PRINTF(",1\r\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) { + uint32_t destval; + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(",1\r\n"); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (*destreg, 1); + *destreg = destval; + } else { + uint16_t destval; + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(",1\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t destval; + uint8_t amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + 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\r\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\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + 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) { + uint32_t destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + DECODE_PRINTF(",CL\r\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rmXX_address(mod, rl); + DECODE_PRINTF(",CL\r\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) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(",CL\r\n"); + TRACE_AND_STEP(); + *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(",CL\r\n"); + TRACE_AND_STEP(); + *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd4 +****************************************************************************/ +void x86emuOp_aam(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t a; + + START_OF_INSTR(); + DECODE_PRINTF("AAM\r\n"); + a = fetch_byte_imm(); /* this is a stupid encoding. */ + if (a != 10) { + DECODE_PRINTF("ERROR DECODING AAM\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t a; + + START_OF_INSTR(); + DECODE_PRINTF("AAD\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t addr; + + START_OF_INSTR(); + DECODE_PRINTF("XLAT\r\n"); + TRACE_AND_STEP(); + addr = (uint16_t)(M.x86.R_BX + (uint8_t)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(uint8_t X86EMU_UNUSED(op1)) +{ + int16_t ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOPNE\t"); + ip = (int8_t) fetch_byte_imm(); + ip += (int16_t) M.x86.R_IP; + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int16_t ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOPE\t"); + ip = (int8_t) fetch_byte_imm(); + ip += (int16_t) M.x86.R_IP; + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int16_t ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOP\t"); + ip = (int8_t) fetch_byte_imm(); + ip += (int16_t) M.x86.R_IP; + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t target; + int8_t offset; + + /* jump to byte offset if overflow flag is set */ + START_OF_INSTR(); + DECODE_PRINTF("JCXZ\t"); + offset = (int8_t)fetch_byte_imm(); + target = (uint16_t)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t port; + + START_OF_INSTR(); + DECODE_PRINTF("IN\t"); + port = (uint8_t) fetch_byte_imm(); + DECODE_PRINTF2("%x,AL\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t port; + + START_OF_INSTR(); + DECODE_PRINTF("IN\t"); + port = (uint8_t) fetch_byte_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("EAX,%x\r\n", port); + } else { + DECODE_PRINTF2("AX,%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t port; + + START_OF_INSTR(); + DECODE_PRINTF("OUT\t"); + port = (uint8_t) fetch_byte_imm(); + DECODE_PRINTF2("%x,AL\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint8_t port; + + START_OF_INSTR(); + DECODE_PRINTF("OUT\t"); + port = (uint8_t) fetch_byte_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("%x,EAX\r\n", port); + } else { + DECODE_PRINTF2("%x,AX\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int16_t ip; + + START_OF_INSTR(); + DECODE_PRINTF("CALL\t"); + ip = (int16_t) fetch_word_imm(); + ip += (int16_t) M.x86.R_IP; /* CHECK SIGN */ + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int ip; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\t"); + ip = (int16_t)fetch_word_imm(); + ip += (int16_t)M.x86.R_IP; + DECODE_PRINTF2("%x\r\n", ip); + TRACE_AND_STEP(); + M.x86.R_IP = (uint16_t)ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xea +****************************************************************************/ +void x86emuOp_jump_far_IMM(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t cs, ip; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\tFAR "); + ip = fetch_word_imm(); + cs = fetch_word_imm(); + DECODE_PRINTF2("%x:", cs); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + uint16_t target; + int8_t offset; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\t"); + offset = (int8_t)fetch_byte_imm(); + target = (uint16_t)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("IN\tAL,DX\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("IN\tEAX,DX\r\n"); + } else { + DECODE_PRINTF("IN\tAX,DX\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("OUT\tDX,AL\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("OUT\tDX,EAX\r\n"); + } else { + DECODE_PRINTF("OUT\tDX,AX\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LOCK:\r\n"); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*opcode 0xf1 ILLEGAL OPERATION */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xf2 +****************************************************************************/ +void x86emuOp_repne(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("REPNE\r\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPNE; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf3 +****************************************************************************/ +void x86emuOp_repe(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("REPE\r\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPE; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf4 +****************************************************************************/ +void x86emuOp_halt(uint8_t X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("HALT\r\n"); + TRACE_AND_STEP(); + HALT_SYS(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf5 +****************************************************************************/ +void x86emuOp_cmc(uint8_t X86EMU_UNUSED(op1)) +{ + /* complement the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("CMC\r\n"); + TRACE_AND_STEP(); + TOGGLE_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf6 +****************************************************************************/ +void x86emuOp_opcF6_byte_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint8_t *destreg; + unsigned int destoffset; + uint8_t 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("%x\r\n", srcval); + TRACE_AND_STEP(); + test_byte(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = not_byte(destval); + store_data_byte(destoffset, destval); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = neg_byte(destval); + store_data_byte(destoffset, destval); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_byte(destval); + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_byte(destval); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_byte(destval); + break; + default: + DECODE_PRINTF("\r\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("%x\r\n", srcval); + TRACE_AND_STEP(); + test_byte(*destreg, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = not_byte(*destreg); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = neg_byte(*destreg); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_byte(*destreg); /*!!! */ + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_byte(*destreg); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_byte(*destreg); + break; + default: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + idiv_byte(*destreg); + break; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf7 +****************************************************************************/ +void x86emuOp_opcF7_word_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t 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\r\n", srcval); + TRACE_AND_STEP(); + test_long(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = not_long(destval); + store_data_long(destoffset, destval); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = neg_long(destval); + store_data_long(destoffset, destval); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_long(destval); + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_long(destval); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_long(destval); + break; + case 7: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + idiv_long(destval); + break; + } + } else { + uint16_t 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\r\n", srcval); + TRACE_AND_STEP(); + test_word(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = not_word(destval); + store_data_word(destoffset, destval); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + destval = neg_word(destval); + store_data_word(destoffset, destval); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_word(destval); + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_word(destval); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_word(destval); + break; + case 7: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + idiv_word(destval); + break; + } + } + + } else { /* mod=11 */ + + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t srcval; + + destreg = DECODE_RM_LONG_REGISTER(rl); + + switch (rh) { + case 0: /* test word imm */ + DECODE_PRINTF(","); + srcval = fetch_long_imm(); + DECODE_PRINTF2("%x\r\n", srcval); + TRACE_AND_STEP(); + test_long(*destreg, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = not_long(*destreg); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = neg_long(*destreg); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_long(*destreg); /*!!! */ + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_long(*destreg); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_long(*destreg); + break; + case 7: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + idiv_long(*destreg); + break; + } + } else { + uint16_t *destreg; + uint16_t srcval; + + destreg = DECODE_RM_WORD_REGISTER(rl); + + switch (rh) { + case 0: /* test word imm */ + DECODE_PRINTF(","); + srcval = fetch_word_imm(); + DECODE_PRINTF2("%x\r\n", srcval); + TRACE_AND_STEP(); + test_word(*destreg, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\r\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = not_word(*destreg); + break; + case 3: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = neg_word(*destreg); + break; + case 4: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + mul_word(*destreg); /*!!! */ + break; + case 5: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + imul_word(*destreg); + break; + case 6: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + div_word(*destreg); + break; + case 7: + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + idiv_word(*destreg); + break; + } + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf8 +****************************************************************************/ +void x86emuOp_clc(uint8_t X86EMU_UNUSED(op1)) +{ + /* clear the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("CLC\r\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf9 +****************************************************************************/ +void x86emuOp_stc(uint8_t X86EMU_UNUSED(op1)) +{ + /* set the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("STC\r\n"); + TRACE_AND_STEP(); + SET_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfa +****************************************************************************/ +void x86emuOp_cli(uint8_t X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("CLI\r\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_IF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfb +****************************************************************************/ +void x86emuOp_sti(uint8_t X86EMU_UNUSED(op1)) +{ + /* enable interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("STI\r\n"); + TRACE_AND_STEP(); + SET_FLAG(F_IF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfc +****************************************************************************/ +void x86emuOp_cld(uint8_t X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("CLD\r\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_DF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfd +****************************************************************************/ +void x86emuOp_std(uint8_t X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("STD\r\n"); + TRACE_AND_STEP(); + SET_FLAG(F_DF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfe +****************************************************************************/ +void x86emuOp_opcFE_byte_RM(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + uint8_t destval; + unsigned int destoffset; + uint8_t *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 \r\n", mod); + HALT_SYS(); + break; + } + } +#endif + if (mod < 3) { + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rmXX_address(mod, rl); + DECODE_PRINTF("\r\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("\r\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(uint8_t X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + unsigned int destoffset = 0; + uint16_t *destreg; + uint16_t 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("\r\n"); + switch (rh) { + case 0: /* inc word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = inc_long(destval); + store_data_long(destoffset, destval); + } else { + uint16_t 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) { + uint32_t destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = dec_long(destval); + store_data_long(destoffset, destval); + } else { + uint16_t 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) { + uint32_t destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + push_long(destval); + } else { + uint16_t 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) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = inc_long(*destreg); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = inc_word(*destreg); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = dec_long(*destreg); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = dec_word(*destreg); + } + break; + case 2: /* call word ptr ... */ + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\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 \r\n"); + TRACE_AND_STEP(); + HALT_SYS(); + break; + + case 4: /* jmp ... */ + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + M.x86.R_IP = (uint16_t) (*destreg); + break; + case 5: /* jmp far ptr ... */ + DECODE_PRINTF("OPERATION UNDEFINED 0XFF \r\n"); + TRACE_AND_STEP(); + HALT_SYS(); + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + push_long(*destreg); + } else { + uint16_t *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + push_word(*destreg); + } + break; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*************************************************************************** + * Single byte operation code table: + **************************************************************************/ +void (*x86emu_optab[256])(uint8_t) = +{ +/* 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 */ x86emuOp_esc_coprocess_d8, +/* 0xd9 */ x86emuOp_esc_coprocess_d9, +/* 0xda */ x86emuOp_esc_coprocess_da, +/* 0xdb */ x86emuOp_esc_coprocess_db, +/* 0xdc */ x86emuOp_esc_coprocess_dc, +/* 0xdd */ x86emuOp_esc_coprocess_dd, +/* 0xde */ x86emuOp_esc_coprocess_de, +/* 0xdf */ 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/BaS_gcc/x86emu/ops2.c b/BaS_gcc/x86emu/ops2.c new file mode 100644 index 0000000..d0b1f0c --- /dev/null +++ b/BaS_gcc/x86emu/ops2.c @@ -0,0 +1,1772 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1991-2004 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file includes subroutines to implement the decoding +* and emulation of all the x86 extended two-byte processor +* instructions. +* +****************************************************************************/ + +#include "x86debug.h" +#include "x86emui.h" + +extern unsigned decode_rmXX_address(int mod, int rm); + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +op1 - Instruction op code + +REMARKS: +Handles illegal opcodes. +****************************************************************************/ +void x86emuOp2_illegal_op( + uint8_t op2) +{ + START_OF_INSTR(); + DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\r\n"); + TRACE_REGS(); + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP-2); + DPRINTVALHEXBYTE(": ", op2); + DPRINT(" ILLEGAL EXTENDED X86 OPCODE!\r\n"); + HALT_SYS(); + END_OF_INSTR(); +} + +#define xorl(a,b) (((a) && !(b)) || (!(a) && (b))) + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x80-0x8F +****************************************************************************/ +int x86emu_check_jump_condition(uint8_t 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(uint8_t op2) +{ + int32_t target; + int cond; + + /* conditional jump to word offset. */ + START_OF_INSTR(); + cond = x86emu_check_jump_condition(op2 & 0xF); + target = (int16_t) fetch_word_imm(); + target += (int16_t) M.x86.R_IP; + DECODE_PRINTF2("%x\r\n", target); + TRACE_AND_STEP(); + if (cond) + M.x86.R_IP = (uint16_t)target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x90-0x9F +****************************************************************************/ +void x86emuOp2_set_byte(uint8_t op2) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t *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(uint8_t X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tFS\r\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(uint8_t 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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t srcval; + uint32_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (int16_t)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } else { + uint16_t srcval; + uint16_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (int16_t)*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) { + uint32_t *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 { + uint16_t *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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t 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) { + uint32_t destval; + uint32_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\r\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + uint16_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\r\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) { + uint32_t *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\r\n", shift); + TRACE_AND_STEP(); + *destreg = shld_long(*destreg,*shiftreg,shift); + } else { + uint16_t *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\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval; + uint32_t *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 { + uint16_t destval; + uint16_t *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) { + uint32_t *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 { + uint16_t *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(uint8_t 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(uint8_t X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tGS\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t srcval,mask; + uint32_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (int16_t)*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 { + uint16_t srcval,mask; + uint16_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (int16_t)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (uint16_t)(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) { + uint32_t *srcreg,*shiftreg; + uint32_t 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 { + uint16_t *srcreg,*shiftreg; + uint16_t mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (uint16_t)(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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int destoffset; + uint8_t 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) { + uint32_t destval; + uint32_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\r\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + uint16_t *shiftreg; + + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\r\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) { + uint32_t *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\r\n", shift); + TRACE_AND_STEP(); + *destreg = shrd_long(*destreg,*shiftreg,shift); + } else { + uint16_t *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\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t destval; + uint32_t *shiftreg; + + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\r\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + uint16_t destval; + uint16_t *shiftreg; + + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\r\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) { + uint32_t *destreg,*shiftreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\r\n"); + TRACE_AND_STEP(); + *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL); + } else { + uint16_t *destreg,*shiftreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("IMUL\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (mod < 3) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t srcval; + uint32_t 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,(int32_t)*destreg,(int32_t)srcval); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint32_t)res_lo; + } else { + uint16_t *destreg; + uint16_t srcval; + uint32_t res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = fetch_data_word(srcoffset); + TRACE_AND_STEP(); + res = (int16_t)*destreg * (int16_t)srcval; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint16_t)res; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg,*srcreg; + uint32_t 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,(int32_t)*destreg,(int32_t)*srcreg); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint32_t)res_lo; + } else { + uint16_t *destreg,*srcreg; + uint32_t res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + res = (int16_t)*destreg * (int16_t)*srcreg; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint16_t)res; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb2 +****************************************************************************/ +void x86emuOp2_lss_R_IMM(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + uint16_t *dstreg; + unsigned int 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("\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t srcval,mask; + uint32_t *shiftreg; + + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (int16_t)*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 { + uint16_t srcval,mask; + uint16_t *shiftreg; + + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (int16_t)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (uint16_t)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (uint16_t)(srcval & ~mask)); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *srcreg,*shiftreg; + uint32_t 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 { + uint16_t *srcreg,*shiftreg; + uint16_t mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (uint16_t)(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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + uint16_t *dstreg; + unsigned int 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("\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + uint16_t *dstreg; + unsigned int 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("\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOVZX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (mod < 3) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + uint16_t *destreg; + uint16_t srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint8_t *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + uint16_t *destreg; + uint8_t *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb7 +****************************************************************************/ +void x86emuOp2_movzx_word_R_RM(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + uint32_t *destreg; + uint32_t srcval; + uint16_t *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("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xba +****************************************************************************/ +void x86emuOp2_btX_I(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + uint8_t 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(); + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP-3); + DPRINTVALHEXBYTE(": ", op2); + DPRINTVALHEXBYTE("", (mod<<6)|(rh<<3)|rl); + DPRINT(" ILLEGAL EXTENDED X86 OPCODE EXTENSION!\r\n"); + HALT_SYS(); + } + if (mod < 3) { + + srcoffset = decode_rmXX_address(mod, rl); + shift = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\n", shift); + TRACE_AND_STEP(); + + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t 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 { + uint16_t 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) { + uint32_t *srcreg; + uint32_t mask; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + shift = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\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 { + uint16_t *srcreg; + uint16_t mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + shift = fetch_byte_imm(); + DECODE_PRINTF2(",%d\r\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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int 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) { + uint32_t srcval,mask; + uint32_t *shiftreg; + + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (int16_t)*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 { + uint16_t srcval,mask; + uint16_t *shiftreg; + + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (int16_t)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (uint16_t)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (uint16_t)(srcval ^ mask)); + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *srcreg,*shiftreg; + uint32_t 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 { + uint16_t *srcreg,*shiftreg; + uint16_t mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (uint16_t)(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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("BSF\r\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) { + uint32_t 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 { + uint16_t 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) { + uint32_t *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 { + uint16_t *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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("BSF\r\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) { + uint32_t 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 { + uint16_t 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) { + uint32_t *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 { + uint16_t *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(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOVSX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (mod < 3) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint32_t srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = (int32_t)((int8_t)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + uint16_t *destreg; + uint16_t srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rmXX_address(mod, rl); + srcval = (int16_t)((int8_t)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + } else { /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + uint8_t *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = (int32_t)((int8_t)*srcreg); + } else { + uint16_t *destreg; + uint8_t *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\r\n"); + TRACE_AND_STEP(); + *destreg = (int16_t)((int8_t)*srcreg); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbf +****************************************************************************/ +void x86emuOp2_movsx_word_R_RM(uint8_t X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + unsigned int srcoffset; + uint32_t *destreg; + uint32_t srcval; + uint16_t *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 = (int32_t)((int16_t)fetch_data_word(srcoffset)); + DECODE_PRINTF("\r\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("\r\n"); + TRACE_AND_STEP(); + *destreg = (int32_t)((int16_t)*srcreg); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*************************************************************************** + * Double byte operation code table: + **************************************************************************/ +void (*x86emu_optab2[256])(uint8_t) = +{ +/* 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/BaS_gcc/x86emu/prim_ops.c b/BaS_gcc/x86emu/prim_ops.c new file mode 100644 index 0000000..152e07d --- /dev/null +++ b/BaS_gcc/x86emu/prim_ops.c @@ -0,0 +1,2452 @@ +/**************************************************************************** +* +* 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 OF and AF flag. +* The latter is not so important, but the former is. The overflow +* flag is the XOR of the top two bits of the carry chain for an +* addition (similar for subtraction). Since we do not want to +* simulate the addition in a bitwise manner, we try to calculate the +* carry chain given the two operands and the result. +* +* So, given the following table, which represents the addition of two +* bits, we can derive a formula for the carry chain. +* +* a b cin r cout +* 0 0 0 0 0 +* 0 0 1 1 0 +* 0 1 0 1 0 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 1 +* 1 1 0 0 1 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 1 1 +* 1 | 0 0 1 0 +* +* By inspection, one gets: cc = ab + r'(a + b) +* +* That represents alot of operations, but NO CHOICE.... +* +* Borrow Chain Calculation. +* +* The following table represents the subtraction of two bits, from +* which we can derive a formula for the borrow chain. +* +* a b bin r bout +* 0 0 0 0 0 +* 0 0 1 1 1 +* 0 1 0 1 1 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 0 +* 1 1 0 0 0 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 0 0 +* 1 | 1 1 1 0 +* +* By inspection, one gets: bc = a'b + r(a' + b) +* +****************************************************************************/ + +#define PRIM_OPS_NO_REDEFINE_ASM +#include "x86debug.h" +#include "x86emui.h" + +#define abs(x) ({ \ + int __x = (x); \ + (__x < 0) ? -__x : __x; \ + }) + +#define labs(x) ({ \ + long __x = (x); \ + (__x < 0) ? -__x : __x; \ + }) + +/*------------------------- Global Variables ------------------------------*/ + +static uint32_t 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 ----------------------------*/ + + +/*--------- Side effects helper functions -------*/ + +/**************************************************************************** +REMARKS: +implements side efects for byte operations that don't overflow +****************************************************************************/ + +static void set_parity_flag(uint32_t res) +{ + CONDITIONAL_SET_FLAG(PARITY(res & 0xFF), F_PF); +} + +static void set_szp_flags_8(uint8_t 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(uint16_t 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(uint32_t 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(uint8_t 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(uint16_t 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(uint32_t 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, uint32_t d, uint32_t s, uint32_t res, int set_carry) +{ + uint32_t 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, uint32_t d, uint32_t s, uint32_t res, int set_carry) +{ + uint32_t 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. +****************************************************************************/ +uint16_t aaa_word(uint16_t d) +{ + uint16_t 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 = (uint16_t)(d & 0xFF0F); + set_szp_flags_16(res); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +uint16_t aas_word(uint16_t d) +{ + uint16_t 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 = (uint16_t)(d & 0xFF0F); + set_szp_flags_16(res); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAD instruction and side effects. +****************************************************************************/ +uint16_t aad_word(uint16_t d) +{ + uint16_t l; + uint8_t hb, lb; + + hb = (uint8_t)((d >> 8) & 0xff); + lb = (uint8_t)((d & 0xff)); + l = (uint16_t)((lb + 10 * hb) & 0xFF); + + no_carry_byte_side_eff(l & 0xFF); + return l; +} + +/**************************************************************************** +REMARKS: +Implements the AAM instruction and side effects. +****************************************************************************/ +uint16_t aam_word(uint8_t d) +{ + uint16_t h, l; + + h = (uint16_t)(d / 10); + l = (uint16_t)(d % 10); + l |= (uint16_t)(h << 8); + + no_carry_byte_side_eff(l & 0xFF); + return l; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +uint8_t adc_byte(uint8_t d, uint8_t s) +{ + uint32_t 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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +uint16_t adc_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d + s; + if (ACCESS_FLAG(F_CF)) + res++; + + set_szp_flags_16((uint16_t)res); + calc_carry_chain(16,s,d,res,1); + + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +uint32_t adc_long(uint32_t d, uint32_t s) +{ + uint32_t lo; /* all operands in native machine order */ + uint32_t hi; + uint32_t 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. +****************************************************************************/ +uint8_t add_byte(uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d + s; + set_szp_flags_8((uint8_t)res); + calc_carry_chain(8,s,d,res,1); + + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +uint16_t add_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d + s; + set_szp_flags_16((uint16_t)res); + calc_carry_chain(16,s,d,res,1); + + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +uint32_t add_long(uint32_t d, uint32_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t and_byte(uint8_t d, uint8_t s) +{ + uint8_t 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. +****************************************************************************/ +uint16_t and_word(uint16_t d, uint16_t s) +{ + uint16_t 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. +****************************************************************************/ +uint32_t and_long(uint32_t d, uint32_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t cmp_byte(uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d - s; + set_szp_flags_8((uint8_t)res); + calc_borrow_chain(8, d, s, res, 1); + + return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +uint16_t cmp_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d - s; + set_szp_flags_16((uint16_t)res); + calc_borrow_chain(16, d, s, res, 1); + + return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +uint32_t cmp_long(uint32_t d, uint32_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t daa_byte(uint8_t d) +{ + uint32_t res = d; + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + res += 6; + SET_FLAG(F_AF); + } + if (res > 0x9F || ACCESS_FLAG(F_CF)) { + res += 0x60; + SET_FLAG(F_CF); + } + set_szp_flags_8((uint8_t)res); + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the DAS instruction and side effects. +****************************************************************************/ +uint8_t das_byte(uint8_t d) +{ + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + d -= 6; + SET_FLAG(F_AF); + } + if (d > 0x9F || ACCESS_FLAG(F_CF)) { + d -= 0x60; + SET_FLAG(F_CF); + } + set_szp_flags_8(d); + return d; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +uint8_t dec_byte(uint8_t d) +{ + uint32_t res; /* all operands in native machine order */ + + res = d - 1; + set_szp_flags_8((uint8_t)res); + calc_borrow_chain(8, d, 1, res, 0); + + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +uint16_t dec_word(uint16_t d) +{ + uint32_t res; /* all operands in native machine order */ + + res = d - 1; + set_szp_flags_16((uint16_t)res); + calc_borrow_chain(16, d, 1, res, 0); + + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +uint32_t dec_long(uint32_t d) +{ + uint32_t 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. +****************************************************************************/ +uint8_t inc_byte(uint8_t d) +{ + uint32_t res; /* all operands in native machine order */ + + res = d + 1; + set_szp_flags_8((uint8_t)res); + calc_carry_chain(8, d, 1, res, 0); + + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +uint16_t inc_word(uint16_t d) +{ + uint32_t res; /* all operands in native machine order */ + + res = d + 1; + set_szp_flags_16((uint16_t)res); + calc_carry_chain(16, d, 1, res, 0); + + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +uint32_t inc_long(uint32_t d) +{ + uint32_t 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. +****************************************************************************/ +uint8_t or_byte(uint8_t d, uint8_t s) +{ + uint8_t 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. +****************************************************************************/ +uint16_t or_word(uint16_t d, uint16_t s) +{ + uint16_t 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. +****************************************************************************/ +uint32_t or_long(uint32_t d, uint32_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t neg_byte(uint8_t s) +{ + uint8_t res; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint8_t)-s; + set_szp_flags_8(res); + calc_borrow_chain(8, 0, s, res, 0); + + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +uint16_t neg_word(uint16_t s) +{ + uint16_t res; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint16_t)-s; + set_szp_flags_16((uint16_t)res); + calc_borrow_chain(16, 0, s, res, 0); + + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +uint32_t neg_long(uint32_t s) +{ + uint32_t res; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint32_t)-s; + set_szp_flags_32(res); + calc_borrow_chain(32, 0, s, res, 0); + + return res; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +uint8_t not_byte(uint8_t s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +uint16_t not_word(uint16_t s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +uint32_t not_long(uint32_t s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +uint8_t rcl_byte(uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask, cf; + + /* s is the rotate distance. It varies from 0 - 8. */ + /* have + + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + + want to rotate through the carry by "s" bits. We could + loop, but that's inefficient. So the width is 9, + and we split into three parts: + + The new carry flag (was B_n) + the stuff in B_n-1 .. B_0 + the stuff in B_7 .. B_n+1 + + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the MSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + + IF n > 0 + 1) CF <- b_(8-n) + 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 + 3) B_(n-1) <- cf + 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) + */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(8-n) */ + cf = (d >> (8 - cnt)) & 0x1; + + /* get the low stuff which rotated + into the range B_7 .. B_cnt */ + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */ + /* note that the right hand side done by the mask */ + res = (d << cnt) & 0xff; + + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ + /* shift it downward, 7-(n-2) = 9-n positions. + and mask off the result before or'ing in. + */ + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (9 - cnt)) & mask; + + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + /* B_(n-1) <- cf */ + res |= 1 << (cnt - 1); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + /* parenthesized this expression since it appears to + be causing OF to be misset */ + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), + F_OF); + + } + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +uint16_t rcl_word(uint16_t d, uint8_t 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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +uint32_t rcl_long(uint32_t d, uint8_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t rcr_byte(uint8_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the LSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + + IF n > 0 + 1) CF <- b_(n-1) + 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 3) B_(8-n) <- cf + 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) + */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(n-1) */ + if (cnt == 1) { + cf = d & 0x1; + /* note hackery here. Access_flag(..) evaluates to either + 0 if flag not set + non-zero if flag is set. + doing access_flag(..) != 0 casts that into either + 0..1 in any representation of the flags register + (i.e. packed bit array or unpacked.) + */ + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */ + /* note that the right hand side done by the mask + This is effectively done by shifting the + object to the right. The result must be masked, + in case the object came in and was treated + as a negative number. Needed??? */ + + 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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +uint16_t rcr_word(uint16_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 17) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (16 - cnt)) - 1; + res = (d >> cnt) & mask; + res |= (d << (17 - cnt)); + if (ACCESS_FLAG(F_CF)) { + res |= 1 << (16 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), + F_OF); + } + } + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +uint32_t rcr_long(uint32_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 33) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (32 - cnt)) - 1; + res = (d >> cnt) & mask; + if (cnt != 1) + res |= (d << (33 - cnt)); + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + res |= 1 << (32 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), + F_OF); + } + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +uint8_t rol_byte(uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + /* rotate left */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + CF B_7 ... B_0 + + The new rotate is done mod 8. + Much simpler than the "rcl" or "rcr" operations. + + IF n > 0 + 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) + 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) + */ + res = d; + if ((cnt = s % 8) != 0) { + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */ + res = (d << cnt); + + /* 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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +uint16_t rol_word(uint16_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (16 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 14) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +uint32_t rol_long(uint32_t d, uint8_t s) +{ + uint32_t res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (32 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 30) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +uint8_t ror_byte(uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + /* rotate right */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + B_7 ... B_0 + + The rotate is done mod 8. + + IF n > 0 + 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) + */ + res = d; + if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */ + /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */ + res = (d << (8 - cnt)); + + /* 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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +uint16_t ror_word(uint16_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << (16 - cnt)); + mask = (1 << (16 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + } + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +uint32_t ror_long(uint32_t d, uint8_t s) +{ + uint32_t res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << (32 - cnt)); + mask = (1 << (32 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +uint8_t shl_byte(uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + + /* last bit shifted out goes into carry flag */ + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_8((uint8_t)res); + } else { + res = (uint8_t) 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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +uint16_t shl_word(uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_16((uint16_t)res); + } else { + res = (uint16_t) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG( + (((res & 0x8000) == 0x8000) ^ + (ACCESS_FLAG(F_CF) != 0)), + F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +uint32_t shl_long(uint32_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_32((uint32_t)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. +****************************************************************************/ +uint8_t shr_byte(uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_8((uint8_t)res); + } else { + res = (uint8_t) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +uint16_t shr_word(uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +uint32_t shr_long(uint32_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_32((uint32_t)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. +****************************************************************************/ +uint8_t sar_byte(uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf, mask, sf; + + res = d; + sf = d & 0x80; + cnt = s % 8; + if (cnt > 0 && cnt < 8) { + mask = (1 << (8 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + set_szp_flags_8((uint8_t)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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +uint16_t sar_word(uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf, mask, sf; + + sf = d & 0x8000; + cnt = s % 16; + res = d; + if (cnt > 0 && cnt < 16) { + mask = (1 << (16 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +uint32_t sar_long(uint32_t d, uint8_t s) +{ + uint32_t cnt, res, cf, mask, sf; + + sf = d & 0x80000000; + cnt = s % 32; + res = d; + if (cnt > 0 && cnt < 32) { + mask = (1 << (32 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + 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. +****************************************************************************/ +uint16_t shld_word (uint16_t d, uint16_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = (d << cnt) | (fill >> (16-cnt)); + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +uint32_t shld_long (uint32_t d, uint32_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = (d << cnt) | (fill >> (32-cnt)); + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_32((uint32_t)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. +****************************************************************************/ +uint16_t shrd_word (uint16_t d, uint16_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +uint32_t shrd_long (uint32_t d, uint32_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + set_szp_flags_32((uint32_t)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. +****************************************************************************/ +uint8_t sbb_byte(uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + set_szp_flags_8((uint8_t)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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +uint16_t sbb_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +uint32_t sbb_long(uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + + 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. +****************************************************************************/ +uint8_t sub_byte(uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + set_szp_flags_8((uint8_t)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 (uint8_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +uint16_t sub_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + set_szp_flags_16((uint16_t)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 (uint16_t)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +uint32_t sub_long(uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t 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(uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + set_szp_flags_8((uint8_t)res); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_word(uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + set_szp_flags_16((uint16_t)res); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_long(uint32_t d, uint32_t s) +{ + uint32_t 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. +****************************************************************************/ +uint8_t xor_byte(uint8_t d, uint8_t s) +{ + uint8_t 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. +****************************************************************************/ +uint16_t xor_word(uint16_t d, uint16_t s) +{ + uint16_t 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. +****************************************************************************/ +uint32_t xor_long(uint32_t d, uint32_t s) +{ + uint32_t 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(uint8_t s) +{ + int16_t res = (int16_t)((int8_t)M.x86.R_AL * (int8_t)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(uint16_t s) +{ + int32_t res = (int16_t)M.x86.R_AX * (int16_t)s; + + M.x86.R_AX = (uint16_t)res; + M.x86.R_DX = (uint16_t)(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(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s) +{ +#ifdef __HAS_LONG_LONG__ + s64 res = (s64)d * (s64)s; + + *res_lo = (uint32_t)res; + *res_hi = (uint32_t)(res >> 32); +#else + uint32_t d_lo,d_hi,d_sign; + uint32_t s_lo,s_hi,s_sign; + uint32_t 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(uint32_t 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(uint8_t s) +{ + uint16_t res = (uint16_t)(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(uint16_t s) +{ + uint32_t res = M.x86.R_AX * s; + + M.x86.R_AX = (uint16_t)res; + M.x86.R_DX = (uint16_t)(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(uint32_t s) +{ +#ifdef __HAS_LONG_LONG__ + u64 res = (uint32_t)M.x86.R_EAX * (uint32_t)s; + + M.x86.R_EAX = (uint32_t)res; + M.x86.R_EDX = (uint32_t)(res >> 32); +#else + uint32_t a,a_lo,a_hi; + uint32_t s_lo,s_hi; + uint32_t 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(uint8_t s) +{ + int32_t dvd, div, mod; + + dvd = (int16_t)M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (int8_t)s; + mod = dvd % (int8_t)s; + if (abs(div) > 0x7f) { + x86emu_intr_raise(0); + return; + } + M.x86.R_AL = (int8_t) div; + M.x86.R_AH = (int8_t) mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_word(uint16_t s) +{ + int32_t dvd, div, mod; + + dvd = (((int32_t)M.x86.R_DX) << 16) | M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (int16_t)s; + mod = dvd % (int16_t)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 = (uint16_t)div; + M.x86.R_DX = (uint16_t)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_long(uint32_t 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 / (int32_t)s; + mod = dvd % (int32_t)s; + if (abs(div) > 0x7fffffff) { + x86emu_intr_raise(0); + return; + } +#else + int32_t div = 0, mod; + int32_t h_dvd = M.x86.R_EDX; + uint32_t l_dvd = M.x86.R_EAX; + uint32_t abs_s = s & 0x7FFFFFFF; + uint32_t abs_h_dvd = h_dvd & 0x7FFFFFFF; + uint32_t h_s = abs_s >> 1; + uint32_t 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 = (uint32_t)div; + M.x86.R_EDX = (uint32_t)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_byte(uint8_t s) +{ + uint32_t dvd, div, mod; + + dvd = M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (uint8_t)s; + mod = dvd % (uint8_t)s; + if (abs(div) > 0xff) { + x86emu_intr_raise(0); + return; + } + M.x86.R_AL = (uint8_t)div; + M.x86.R_AH = (uint8_t)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_word(uint16_t s) +{ + uint32_t dvd, div, mod; + + dvd = (((uint32_t)M.x86.R_DX) << 16) | M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (uint16_t)s; + mod = dvd % (uint16_t)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 = (uint16_t)div; + M.x86.R_DX = (uint16_t)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_long(uint32_t 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 / (uint32_t)s; + mod = dvd % (uint32_t)s; + if (abs(div) > 0xffffffff) { + x86emu_intr_raise(0); + return; + } +#else + int32_t div = 0, mod; + int32_t h_dvd = M.x86.R_EDX; + uint32_t l_dvd = M.x86.R_EAX; + + uint32_t h_s = s; + uint32_t 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 = (uint32_t)div; + M.x86.R_EDX = (uint32_t)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. */ + uint32_t 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. */ + uint32_t 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. +****************************************************************************/ +uint16_t 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(uint16_t w) +{ +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + M.x86.R_SP -= 2; + (*sys_wrw)(((uint32_t)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(uint32_t w) +{ +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + M.x86.R_SP -= 4; + (*sys_wrl)(((uint32_t)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! +****************************************************************************/ +uint16_t pop_word(void) +{ + uint16_t res; + +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + res = (*sys_rdw)(((uint32_t)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! +****************************************************************************/ +uint32_t pop_long(void) +{ + uint32_t res; + +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + res = (*sys_rdl)(((uint32_t)M.x86.R_SS << 4) + M.x86.R_SP); + M.x86.R_SP += 4; + return res; +} + diff --git a/BaS_gcc/x86emu/sys.c b/BaS_gcc/x86emu/sys.c new file mode 100644 index 0000000..1016be1 --- /dev/null +++ b/BaS_gcc/x86emu/sys.c @@ -0,0 +1,620 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 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 with limited usefulness. For real +* uses these functions will most likely be overriden by the +* user library. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/sys.c,v 1.5 2000/08/23 22:10:01 tsi Exp $ */ + +#include "radeonfb.h" +#include "pci.h" + +#include "x86emu.h" +#include "x86regs.h" +#include "x86debug.h" +#include "x86prim_ops.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +extern uint8_t inb(uint16_t port); +extern uint16_t inw(uint16_t port); +extern uint32_t inl(uint16_t port); +extern void outb(uint8_t val, uint16_t port); +extern void outw(uint16_t val, uint16_t port); +extern void outl(uint32_t val, uint16_t port); +extern uint16_t swap_short(uint16_t val); +extern uint32_t swap_long(uint32_t val); + +/*------------------------- Global Variables ------------------------------*/ + +X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */ +X86EMU_intrFuncs _X86EMU_intrTab[256]; +extern struct radeonfb_info *rinfo_biosemu; +extern uint32_t offset_mem; + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Byte value read from emulator memory. + +REMARKS: +Reads a byte value from the emulator memory. +****************************************************************************/ +uint8_t X86API rdb(uint32_t addr) +{ + uint8_t val; + + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("rdb(", addr); +#endif + val = *(uint8_t *)(offset_mem+addr); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif + } + else + { +#if 0 + if(addr >= M.mem_size) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#endif +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + val = *(uint8_t *)(M.mem_base + addr); + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXBYTE(" 1 -> ", val); + DPRINT("\r\n"); + } ) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Word value read from emulator memory. + +REMARKS: +Reads a word value from the emulator memory. +****************************************************************************/ +uint16_t X86API rdw(uint32_t addr) +{ + uint16_t val; + + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("rdw(", addr); +#endif + val = swpw(*(uint16_t *)(offset_mem+addr)); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif + } + else + { +#if 0 + if(addr > M.mem_size - 2) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#endif +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + val = (uint16_t)(*(uint8_t *)(M.mem_base + addr)); + val |= (((uint16_t)( *(uint8_t *)(M.mem_base + addr + 1))) << 8); +// val = *(uint16_t *)(M.mem_base + addr); + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXWORD(" 2 -> ", val); + DPRINT("\r\n"); + } ) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Long value read from emulator memory. +REMARKS: +Reads a long value from the emulator memory. +****************************************************************************/ +uint32_t X86API rdl(uint32_t addr) +{ + uint32_t val; + + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("rdl(", addr); +#endif + val = swap_long(*(uint32_t *)(offset_mem+addr)); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif + } + else + { +#if 0 + if(addr > M.mem_size - 4) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#endif +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + val = swap_long(*(uint32_t *)(M.mem_base + addr)); +// val = *(uint32_t *)(M.mem_base + addr); + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXLONG(" 4 -> ", val); + DPRINT("\r\n"); + } ) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a byte value to emulator memory. +****************************************************************************/ +void X86API wrb(uint32_t addr, uint8_t val) +{ + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("wrb(", addr); + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif + *(uint8_t *)(offset_mem+addr) = val; + } + else + { + if(addr >= M.mem_size) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + *(uint8_t *)(M.mem_base + addr) = val; + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXBYTE(" 1 <- ", val); + DPRINT("\r\n"); + } ) +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a word value to emulator memory. +****************************************************************************/ +void X86API wrw(uint32_t addr, uint16_t val) +{ + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("wrw(", addr); + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif +#ifdef DIRECT_ACCESS + *(uint16_t *)(offset_mem+addr) = swap_short(val); +#else +#ifdef PCI_XBIOS + write_mem_word(rinfo_biosemu->handle, offset_mem+addr, val); +#else + Write_mem_word(rinfo_biosemu->handle, offset_mem+addr, val); +#endif +#endif + } + else + { + if(addr > M.mem_size - 2) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + *(uint8_t *)(M.mem_base + addr) = (uint8_t)val; + *(uint8_t *)(M.mem_base + addr + 1) = (uint8_t)(val >> 8); +// *(uint16_t *)(M.mem_base + addr) = val; + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXWORD(" 2 <- ", val); + DPRINT("\r\n"); + } ) +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a long value to emulator memory. +****************************************************************************/ +void X86API wrl(uint32_t addr, uint32_t val) +{ + if((addr >= 0xA0000) && (addr <= 0xBFFFF)) + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("wrl(", addr); + DPRINTVALHEX(") = ", val); + DPRINT("\r\n"); +#endif +#ifdef DIRECT_ACCESS + *(uint32_t *)(offset_mem+addr) = swap_long(val); +#else +#ifdef PCI_XBIOS + write_mem_longword(rinfo_biosemu->handle, offset_mem+addr, val); +#else + Write_mem_longword(rinfo_biosemu->handle, offset_mem+addr, val); +#endif +#endif + } + else + { + if(addr > M.mem_size - 4) + { + DB( { DPRINTVALHEX("mem_ptr: address ", addr); + DPRINT(" out of range!\r\n"); } ) + HALT_SYS(); + } +#if 0 + if(addr < 0x200) + { + DPRINTVALHEXWORD("", M.x86.R_CS); + DPRINTVALHEXWORD(":", M.x86.R_IP); + DPRINTVALHEX(" updating int vector ", addr >> 2); + DPRINT("\r\n"); + } +#endif + *(uint32_t *)(M.mem_base + addr) = swap_long(val); +// *(uint32_t *)(M.mem_base + addr) = val; + } + DB(if (DEBUG_MEM_TRACE()) + { + DPRINTVALHEXLONG("", addr); + DPRINTVALHEXLONG(" 4 <- ", val); + DPRINT("\r\n"); + } ) +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO byte read function. Doesn't perform real inb. +****************************************************************************/ +static uint8_t X86API p_inb(X86EMU_pioAddr addr) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXWORD("inb ", addr); + DPRINT(" \r\n"); + } ) + return inb(addr); +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO word read function. Doesn't perform real inw. +****************************************************************************/ +static uint16_t X86API p_inw(X86EMU_pioAddr addr) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXWORD("inw ", addr); + DPRINT(" \r\n"); + } ) + return inw(addr); +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO long read function. Doesn't perform real inl. +****************************************************************************/ +static uint32_t X86API p_inl(X86EMU_pioAddr addr) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXWORD("inl ", addr); + DPRINT(" \r\n"); + } ) + return inl(addr); +} + +/**************************************************************************** +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, uint8_t val) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXBYTE("outb ", val); + DPRINTVALHEXWORD(" -> ", addr); + DPRINT(" \r\n"); + } ) + outb(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, uint16_t val) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXWORD("outw ", (unsigned long)val); + DPRINTVALHEXWORD(" -> ", addr); + DPRINT(" \r\n"); + } ) + outw(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, uint32_t val) +{ + DB(if (DEBUG_IO_TRACE()) + { + DPRINTVALHEXLONG("outl ", val); + DPRINTVALHEXWORD(" -> ", addr); + DPRINT(" \r\n"); + } ) + outl(val, addr); + return; +} + +/*------------------------- Global Variables ------------------------------*/ + +uint8_t(X86APIP sys_rdb) (uint32_t addr) = rdb; +uint16_t(X86APIP sys_rdw) (uint32_t addr) = rdw; +uint32_t(X86APIP sys_rdl) (uint32_t addr) = rdl; +void (X86APIP sys_wrb) (uint32_t addr, uint8_t val) = wrb; +void (X86APIP sys_wrw) (uint32_t addr, uint16_t val) = wrw; +void (X86APIP sys_wrl) (uint32_t addr, uint32_t val) = wrl; +uint8_t(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb; +uint16_t(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw; +uint32_t(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl; +void (X86APIP sys_outb) (X86EMU_pioAddr addr, uint8_t val) = p_outb; +void (X86APIP sys_outw) (X86EMU_pioAddr addr, uint16_t val) = p_outw; +void (X86APIP sys_outl) (X86EMU_pioAddr addr, uint32_t val) = p_outl; + +/*----------------------------- Setup -------------------------------------*/ + +#if 0 // cannot works whith data in flash +/**************************************************************************** +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; +} +#endif + +/**************************************************************************** +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((uint16_t) 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; +} + +void X86EMU_setMemBase(void *base, unsigned long size) +{ + M.mem_base = (int) base; + M.mem_size = size; +} diff --git a/BaS_gcc/x86emu/x86pcibios.c b/BaS_gcc/x86emu/x86pcibios.c new file mode 100644 index 0000000..212ebd7 --- /dev/null +++ b/BaS_gcc/x86emu/x86pcibios.c @@ -0,0 +1,243 @@ +#include "radeonfb.h" +#include "pci.h" +#include "x86emu.h" +#include "x86pcibios.h" + +extern unsigned short offset_port; + +int x86_pcibios_emulator() +{ + int ret = 0; + unsigned long dev; + + switch (X86_AX) { + case PCI_BIOS_PRESENT: +#ifdef DEBUG_X86EMU_PCI + DPRINT("PCI_BIOS_PRESENT\r\n"); +#endif + X86_AH = 0x00; /* no config space/special cycle support */ + X86_AL = 0x01; /* config mechanism 1 */ + X86_EDX = 'P' | 'C' << 8 | 'I' << 16 | ' ' << 24; + X86_EBX = 0x0210; /* Version 2.10 */ + X86_ECX = 0xFF00; /* FixME: Max bus number */ + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + case FIND_PCI_DEVICE: + /* FixME: support SI != 0 */ + // vendor, device +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("FIND_PCI_DEVICE vendor ", X86_DX); + DPRINTVALHEX(" device ", X86_CX); +#endif + dev = pci_find_device((unsigned long) X86_DX, ((unsigned long)X86_CX), 0); + + if (dev != 0) { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_BH = PCI_BUS_FROM_HANDLE(dev); + //X86_BH = (char)(dev >> 16) / PCI_MAX_FUNCTION); // dev->bus->secondary; + X86_BL = PCI_DEVICE_FROM_HANDLE(dev) << 3 | PCI_FUNCTION_FROM_HANDLE(dev); + //X86_BL = (char)dev; // dev->path.u.pci.devfn; + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + } else { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... error\r\n"); +#endif + X86_AH = DEVICE_NOT_FOUND; + X86_EFLAGS |= FB_CF; /* set carry flag */ + ret = 0; + } + break; + case FIND_PCI_CLASS_CODE: + /* FixME: support SI != 0 */ +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX("FIND_PCI_CLASS_CODE ", X86_ECX); +#endif + dev = pci_find_classcode(X86_ECX, 0); + if (dev != 0) { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_BH = PCI_BUS_FROM_HANDLE(dev); + X86_BL = PCI_DEVICE_FROM_HANDLE(dev) << 3 | PCI_FUNCTION_FROM_HANDLE(dev); + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + } else { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... error\r\n"); +#endif + X86_AH = DEVICE_NOT_FOUND; + X86_EFLAGS |= FB_CF; /* set carry flag */ + ret = 0; + } + break; + case READ_CONFIG_BYTE: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("READ_CONFIG_BYTE bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); +#endif + X86_CL = pci_read_config_byte(dev, X86_DI); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(" value ", X86_CL); + DPRINT("\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + case READ_CONFIG_WORD: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("READ_CONFIG_WORD bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); +#endif + if(X86_DI == PCIBAR1) + X86_CX = offset_port + 1; + else + X86_CX = pci_read_config_word(dev, X86_DI); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(" value ", X86_CX); + DPRINT("\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + case READ_CONFIG_DWORD: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("READ_CONFIG_DWORD bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); +#endif + if(X86_DI == PCIBAR1) + X86_CX = (unsigned long)offset_port+1; + else + X86_ECX = pci_read_config_longword(dev, X86_DI); +#ifdef DEBUG_X86EMU_PCI + DPRINTVALHEX(" value ", X86_ECX); + DPRINT("\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + case WRITE_CONFIG_BYTE: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("READ_CONFIG_BYTE bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); + DPRINTVALHEX(" value ", X86_CL); +#endif + if ((ret = pci_write_config_byte(dev, X86_DI, X86_CL)) == 0) + { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + } else { +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL(" ... error ", ret); + DPRINT("\r\n"); +#endif + X86_AH = DEVICE_NOT_FOUND; + X86_EFLAGS |= FB_CF; /* set carry flag */ + ret = 0; + } + break; + case WRITE_CONFIG_WORD: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("WRITE_CONFIG_WORD bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); + DPRINTVALHEX(" value ", X86_CX); +#endif + if(X86_DI == PCIBAR1) { + offset_port = X86_CX; +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + } + if ((ret = pci_write_config_word(dev, X86_DI, X86_CX)) == 0) + { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + } else { +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL(" ... error ", ret); + DPRINT("\r\n"); +#endif + X86_AH = DEVICE_NOT_FOUND; + X86_EFLAGS |= FB_CF; /* set carry flag */ + ret = 0; + } + break; + case WRITE_CONFIG_DWORD: + // bus, devfn +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL("WRITE_CONFIG_DWORD bus ", X86_BH); + DPRINTVAL(" devfn ", X86_BL); + DPRINTVALHEX(" reg ", X86_DI); + DPRINTVALHEX(" value ", X86_ECX); +#endif + if(X86_DI == PCIBAR1) { + offset_port = (unsigned short)X86_ECX & 0xFFFC; +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + break; + } + if ((ret = pci_write_config_longword(dev, X86_DI, X86_ECX)) == 0) + { +#ifdef DEBUG_X86EMU_PCI + DPRINT(" ... OK\r\n"); +#endif + X86_AH = SUCCESSFUL; + X86_EFLAGS &= ~FB_CF; /* clear carry flag */ + ret = 1; + } + else + { +#ifdef DEBUG_X86EMU_PCI + DPRINTVAL(" ... error ", ret); + DPRINT("\r\n"); +#endif + X86_AH = DEVICE_NOT_FOUND; + X86_EFLAGS |= FB_CF; /* set carry flag */ + ret = 0; + } + break; + default: +#ifdef DEBUG_X86EMU_PCI + DPRINT("PCI_BIOS FUNC_NOT_SUPPORTED\r\n"); +#endif + X86_AH = FUNC_NOT_SUPPORTED; + X86_EFLAGS |= FB_CF; + break; + } + + return ret; +}