summaryrefslogtreecommitdiffstats
path: root/private/mvdm/softpc.new/base/ccpu386/c_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/softpc.new/base/ccpu386/c_main.c')
-rw-r--r--private/mvdm/softpc.new/base/ccpu386/c_main.c4940
1 files changed, 4940 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/base/ccpu386/c_main.c b/private/mvdm/softpc.new/base/ccpu386/c_main.c
new file mode 100644
index 000000000..24b5582a5
--- /dev/null
+++ b/private/mvdm/softpc.new/base/ccpu386/c_main.c
@@ -0,0 +1,4940 @@
+/*[
+
+c_main.c
+
+LOCAL CHAR SccsID[]="@(#)c_main.c 1.96 04/11/95";
+
+Main routine for CPU emulator.
+------------------------------
+
+All instruction decoding and addressing is controlled here.
+Actual worker routines are spun off elsewhere.
+
+]*/
+
+#include <insignia.h>
+#include <host_def.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#include <xt.h> /* needed by bios.h */
+#include <sas.h> /* need memory(M) */
+#include <ccpusas4.h> /* the cpu internal sas bits */
+#ifdef PIG
+#include <Cpu_c.h> /* Intel pointer manipulation macros */
+#endif /* PIG */
+#include CpuH
+/* #include "event.h" */ /* Event Manager */
+#include <bios.h> /* need access to bop */
+#include <debug.h>
+#include <config.h>
+#ifdef NTVDM
+#include <ntthread.h>
+#endif
+
+#include <c_main.h> /* C CPU definitions-interfaces */
+#include <c_page.h> /* Paging Interface */
+#include <c_mem.h> /* CPU - Memory Interface */
+#include <c_intr.h> /* Interrupt Interface */
+#include <c_debug.h> /* Debug Regs and Breakpoint Interface */
+#include <c_oprnd.h> /* Operand decoding functions(macros) */
+#include <c_xcptn.h>
+#include <c_reg.h>
+#include <c_page.h>
+#include <c_intr.h>
+#include <c_debug.h>
+#include <c_oprnd.h>
+#include <c_bsic.h>
+#include <ccpupig.h>
+#include <fault.h>
+
+#include <aaa.h> /* The workers */
+#include <aad.h> /* ... */
+#include <aam.h> /* ... */
+#include <aas.h> /* ... */
+#include <adc.h> /* ... */
+#include <add.h> /* ... */
+#include <and.h> /* ... */
+#include <arpl.h> /* ... */
+#include <bound.h> /* ... */
+#include <bsf.h> /* ... */
+#include <bsr.h> /* ... */
+#include <bt.h> /* ... */
+#include <btc.h> /* ... */
+#include <btr.h> /* ... */
+#include <bts.h> /* ... */
+#include <call.h> /* ... */
+#include <cbw.h> /* ... */
+#include <cdq.h> /* ... */
+#include <clc.h> /* ... */
+#include <cld.h> /* ... */
+#include <cli.h> /* ... */
+#include <clts.h> /* ... */
+#include <cmc.h> /* ... */
+#include <cmp.h> /* CMP, CMPS, SCAS */
+#include <cwd.h> /* ... */
+#include <cwde.h> /* ... */
+#include <daa.h> /* ... */
+#include <das.h> /* ... */
+#include <dec.h> /* ... */
+#include <div.h> /* ... */
+#include <enter.h> /* ... */
+#include <idiv.h> /* ... */
+#include <imul.h> /* ... */
+#include <in.h> /* ... */
+#include <inc.h> /* ... */
+#include <into.h> /* ... */
+#include <intx.h> /* INT, INT 3 */
+#include <iret.h> /* ... */
+#include <jcxz.h> /* JCXZ, JECXZ */
+#include <jmp.h> /* ... */
+#include <jxx.h> /* JB, JBE, JL, JLE, JNB, JNBE, JNL, JNLE, */
+ /* JNO, JNP, JNS, JNZ, JO, JP, JS, JZ */
+#include <lahf.h> /* ... */
+#include <lar.h> /* ... */
+#include <lea.h> /* ... */
+#include <leave.h> /* ... */
+#include <lgdt.h> /* ... */
+#include <lidt.h> /* ... */
+#include <lldt.h> /* ... */
+#include <lmsw.h> /* ... */
+#include <loopxx.h> /* LOOP, LOOPE, LOOPNE */
+#include <lsl.h> /* ... */
+#include <ltr.h> /* ... */
+#include <lxs.h> /* LDS, LES, LFS, LGS, LSS */
+#include <mov.h> /* LODS, MOV, MOVZX, MOVS, STOS */
+#include <movsx.h> /* ... */
+#include <mul.h> /* ... */
+#include <neg.h> /* ... */
+#include <nop.h> /* ... */
+#include <not.h> /* ... */
+#include <out.h> /* ... */
+#include <or.h> /* ... */
+#include <pop.h> /* ... */
+#include <popa.h> /* ... */
+#include <popf.h> /* ... */
+#include <push.h> /* ... */
+#include <pusha.h> /* ... */
+#include <pushf.h> /* ... */
+#include <rcl.h> /* ... */
+#include <rcr.h> /* ... */
+#include <ret.h> /* ... */
+#include <rol.h> /* ... */
+#include <ror.h> /* ... */
+#include <rsrvd.h> /* ... */
+#include <sahf.h> /* ... */
+#include <sar.h> /* ... */
+#include <sbb.h> /* ... */
+#include <setxx.h> /* SETB, SETBE, SETL, SETLE, SETNB, SETNBE, */
+ /* SETNL, SETNLE, SETNO, SETNP, SETNS, SETNZ, */
+ /* SETO, SETP, SETS, SETZ */
+#include <sgdt.h> /* ... */
+#include <shl.h> /* ... */
+#include <shld.h> /* ... */
+#include <shr.h> /* ... */
+#include <shrd.h> /* ... */
+#include <sidt.h> /* ... */
+#include <sldt.h> /* ... */
+#include <smsw.h> /* ... */
+#include <stc.h> /* ... */
+#include <std.h> /* ... */
+#include <sti.h> /* ... */
+#include <str.h> /* ... */
+#include <sub.h> /* ... */
+#include <test.h> /* ... */
+#include <verr.h> /* ... */
+#include <verw.h> /* ... */
+#include <wait.h> /* ... */
+#include <xchg.h> /* ... */
+#include <xlat.h> /* ... */
+#include <xor.h> /* ... */
+#include <zfrsrvd.h> /* ... */
+
+#ifdef CPU_486
+#include <bswap.h> /* ... */
+#include <cmpxchg.h> /* ... */
+#include <invd.h> /* ... */
+#include <invlpg.h> /* ... */
+#include <wbinvd.h> /* ... */
+#include <xadd.h> /* ... */
+#endif /* CPU_486 */
+
+#define FIX_BT_BUG /* Of course we want the bug fixed! */
+
+#define SYNCH_BOTH_WAYS /* Do a PIG_SYNCH() on not-taken conditionals as well */
+
+/*
+ Types and constants local to this module.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+typedef union
+ {
+ IU32 sng; /* Single Part Operand */
+ IU32 mlt[2]; /* Multiple (two) Part Operand */
+ DOUBLE flt; /* Floating Point Operand */
+ IU8 npxbuff[108];
+ } OPERAND;
+
+/*
+ The allowable types of repeat prefix.
+ */
+#define REP_CLR (IU8)0
+#define REP_NE (IU8)1
+#define REP_E (IU8)2
+
+/*
+ Offsets to Low byte, High byte and Word parts of Double Word Regs.
+ */
+#ifdef LITTLEND
+
+#define L_OFF 0
+#define H_OFF 1
+#define X_OFF 0
+
+#else /* BIGEND */
+
+#define L_OFF 3
+#define H_OFF 2
+#define X_OFF 2
+
+#endif /* LITTLEND */
+
+/* CPU hardware interrupt definitions */
+#define CPU_HW_INT_MASK (1 << 0)
+
+#ifdef SFELLOW
+ /* for raising NPX interrupt */
+#define IRQ5_SLAVE_PIC 5
+#endif /* SFELLOW */
+
+/* CPU hardware interrupt definitions */
+#define CPU_HW_INT_MASK (1 << 0)
+
+/* Masks for external CPU events. */
+#define CPU_SIGIO_EXCEPTION_MASK (1 << 12)
+#define CPU_SAD_EXCEPTION_MASK (1 << 13)
+#define CPU_RESET_EXCEPTION_MASK (1 << 14)
+#define CPU_SIGALRM_EXCEPTION_MASK (1 << 15)
+#ifdef SFELLOW
+#define CPU_HW_NPX_INT_MASK (1 << 16)
+#endif /* SFELLOW */
+
+LOCAL IU16 cpu_hw_interrupt_number;
+#if defined(SFELLOW)
+extern IU32 cpu_interrupt_map ;
+#else
+LOCAL IUM32 cpu_interrupt_map = 0;
+#endif /* SFELLOW */
+
+
+GLOBAL IBOOL took_relative_jump;
+extern IBOOL NpxIntrNeeded;
+GLOBAL IBOOL took_absolute_toc;
+LOCAL IBOOL single_instruction_delay ;
+LOCAL IBOOL single_instruction_delay_enable ;
+
+/*
+ Define Maximun valid segment register in a 3-bit 'reg' field.
+ */
+#define MAX_VALID_SEG 5
+
+/*
+ Define lowest modRM for register (rather than memory) addressing.
+ */
+#define LOWEST_REG_MODRM 0xc0
+
+GLOBAL VOID clear_any_thingies IFN0()
+{
+ cpu_interrupt_map &= ~CPU_SIGALRM_EXCEPTION_MASK;
+}
+
+
+/*
+ Prototype our internal functions.
+ */
+LOCAL VOID ccpu
+
+IPT1(
+ ISM32, single_step
+
+ );
+
+LOCAL VOID check_io_permission_map IPT2(IU32, port_addr, IUM8, port_width);
+
+/*
+ FRIG for delayed interrupts to *not* occur when IO registers
+ are accessed from our non CPU C code.
+ */
+ISM32 in_C;
+
+LOCAL BOOL quick_mode = FALSE; /* true if no special processing (trap
+ flag, interrupts, yoda...) is needed
+ between instructions. All flow of
+ control insts. and I/O insts. force
+ an exit from quick mode. IE. linear
+ sequences of CPU functions should
+ normally run in quick mode. */
+
+
+#ifdef PIG
+
+/* We must delay the actual synch (i.e. the c_cpu_unsimulate)
+ * until after processing any trap/breakpoint stuff.
+ */
+#define PIG_SYNCH(action) \
+ SYNCH_TICK(); \
+ if (ccpu_pig_enabled) \
+ { \
+ pig_cpu_action = (action); \
+ quick_mode = FALSE; \
+ pig_synch_required = TRUE; \
+ CANCEL_HOST_IP(); \
+ }
+
+
+LOCAL IBOOL pig_synch_required = FALSE; /* This indicates that the current
+ * instruction needs a pig synch,
+ * and after trap/breakpoint
+ * processing we must return to
+ * the pigger.
+ */
+#else
+
+#define PIG_SYNCH(action) \
+ SYNCH_TICK(); \
+ /* No pig operations */
+
+#endif /* PIG */
+/*
+ Recursive CPU variables. Exception Handling.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define FRAMES 9
+
+/* keep track of each CPU recursion */
+GLOBAL IS32 simulate_level = 0;
+LOCAL jmp_buf longjmp_env_stack[FRAMES];
+
+/* each level has somewhere for exception processing to bail out to */
+LOCAL jmp_buf next_inst[FRAMES];
+
+
+/* When Pigging we save each opcode byte in the last_inst record.
+ * We must check the prefix length so that we dont overflow
+ * our buffer.
+ */
+#ifdef PIG
+LOCAL int prefix_length = 0;
+#define CHECK_PREFIX_LENGTH() \
+ if (++prefix_length >= MAX_INTEL_PREFIX) \
+ Int6();
+#else /* !PIG */
+#define CHECK_PREFIX_LENGTH()
+#endif /* PIG */
+
+/*
+ The emulation register set.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+GLOBAL SEGMENT_REGISTER CCPU_SR[6]; /* Segment Registers */
+
+GLOBAL IU32 CCPU_TR[8]; /* Test Registers */
+
+GLOBAL IU32 CCPU_DR[8]; /* Debug Registers */
+
+GLOBAL IU32 CCPU_CR[4]; /* Control Registers */
+
+GLOBAL IU32 CCPU_GR[8]; /* Double Word General Registers */
+
+/*
+ * WARNING: in the initialisation below, (IU8 *) casts are used
+ * to satify dominatrix compilers that will not allow the use of
+ * IHPE casts for pointer types _in initialisation_.
+ */
+GLOBAL IU16 *CCPU_WR[8] = /* Pointers to the Word Registers */
+ {
+ (IU16 *)((IU8 *)&CCPU_GR[0] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[1] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[2] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[3] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[4] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[5] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[6] + X_OFF),
+ (IU16 *)((IU8 *)&CCPU_GR[7] + X_OFF)
+ };
+
+GLOBAL IU8 *CCPU_BR[8] = /* Pointers to the Byte Registers */
+ {
+ (IU8 *)((IU8 *)&CCPU_GR[0] + L_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[1] + L_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[2] + L_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[3] + L_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[0] + H_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[1] + H_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[2] + H_OFF),
+ (IU8 *)((IU8 *)&CCPU_GR[3] + H_OFF)
+ };
+
+GLOBAL IU32 CCPU_IP; /* The Instruction Pointer */
+GLOBAL SYSTEM_TABLE_ADDRESS_REGISTER CCPU_STAR[2]; /* GDTR and IDTR */
+
+GLOBAL SYSTEM_ADDRESS_REGISTER CCPU_SAR[2]; /* LDTR and TR */
+
+GLOBAL IU32 CCPU_CPL; /* Current Privilege Level */
+
+GLOBAL IU32 CCPU_FLAGS[32]; /* The flags. (EFLAGS) */
+
+ /* We allocate one integer per bit posn, multiple
+ bit fields are aligned to the least significant
+ posn. hence:-
+ CF = 0 PF = 2 AF = 4 ZF = 6
+ SF = 7 TF = 8 IF = 9 DF = 10
+ OF = 11 IOPL = 12 NT = 14 RF = 16
+ VM = 17 AC = 18 */
+
+
+GLOBAL IU32 CCPU_MODE[3]; /* Current Operating Mode */
+
+ /* We allocate one integer per modal condition, as follows:-
+ [0] = current operand size (0=16-bit, 1=32-bit)
+ [1] = current address size (0=16-bit, 1=32-bit)
+ [2] = 'POP' displacement. (0=None,
+ 2=Pop word,
+ 4=Pop double word)
+ Set by POP used by [ESP] addressing modes. */
+
+/*
+ Trap Flag Support.
+
+ Basically if the trap flag is set before an instruction, then when
+ the instruction has been executed a trap is taken. This is why
+ instructions which set the trap flag have a one instruction delay
+ (or apparent one instruction delay) before a trap is first taken.
+ However INT's will clear the trap flag and clear any pending trap
+ at the end of the INT.
+ */
+LOCAL IU32 start_trap;
+
+/*
+ Host Pointer to Instruction Start.
+ (Used in Host IP optimisation)
+ */
+LOCAL IU8 *p_start;
+
+/*
+ Host pointer to point to where host may safely read instruction
+ stream bytes.
+ (Used in Host IP optimisation)
+ */
+GLOBAL IU8 *pg_end;
+
+/*
+ Flag support.
+ */
+GLOBAL IU8 pf_table[] =
+ {
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+ };
+
+/*
+ CPU Heart Beat. A counter is decremented if not zero, and if it becomes
+ zero, this means that an external routine requires an event to occur.
+ The event handling is done through the quick event manager, all we need
+ to do is count down and then call the manager when we get to zero. This
+ mechanism is used to simulate an accurate micro-second
+ timer.
+ */
+LOCAL IU32 cpu_heartbeat;
+GLOBAL IUH PigSynchCount = 0;
+
+IMPORT VOID dispatch_q_event();
+
+#ifndef SFELLOW
+#ifdef SYNCH_TIMERS
+
+#define SYNCH_TICK() \
+ { \
+ PigSynchCount += 1; \
+ if (cpu_heartbeat != 0) \
+ { \
+ if ((--cpu_heartbeat) == 0) \
+ { \
+ dispatch_q_event(); \
+ quick_mode = FALSE; \
+ } \
+ } \
+ }
+
+#define QUICK_EVENT_TICK() /* Nothing */
+
+GLOBAL void SynchTick IFN0()
+{
+ quick_mode = FALSE;
+ SYNCH_TICK();
+}
+
+#else /* !SYNCH_TIMERS */
+
+#define SYNCH_TICK() /* Nothing */
+
+#define QUICK_EVENT_TICK() \
+ { \
+ if (cpu_heartbeat != 0) \
+ { \
+ if ((--cpu_heartbeat) == 0) { \
+ dispatch_q_event(); \
+ quick_mode = FALSE; \
+ } \
+ } \
+ }
+
+#endif /* SYNCH_TIMERS */
+#else /* SFELLOW */
+
+extern IBOOL qEventsToDo;
+extern IBOOL checkForQEvent IPT0();
+
+#define SYNCH_TICK()
+
+#define QUICK_EVENT_TICK() \
+ { \
+ if (qEventsToDo) \
+ { \
+ if (checkForQEvent()) \
+ { \
+ dispatch_q_event(); \
+ quick_mode = FALSE; \
+ } \
+ } \
+ }
+
+#ifdef host_timer_event
+#undef host_timer_event
+#endif
+
+#define host_timer_event()
+#endif /* SFELLOW */
+
+#ifdef SFELLOW
+extern int ica_intack IPT0();
+extern int VectorBase8259Slave IPT0();
+#if !defined(PROD)
+IMPORT IBOOL sf_debug_char_waiting();
+#endif /* !PROD */
+#endif /* SFELLOW */
+
+
+/* debugging stuff */
+IMPORT int do_condition_checks;
+IMPORT void check_I();
+
+/*
+ Define macros which allow Intel and host IP formats to be maintained
+ seperately. This is an 'unclean' implementation but does give a
+ significant performance boost. Specifically it means during the
+ decode of one Intel instruction we can use a host pointer into
+ memory and avoid incrementing the Intel IP on a byte by byte basis.
+ */
+
+/*
+ * SasWrapMask
+ */
+
+GLOBAL PHY_ADDR SasWrapMask = 0xfffff;
+
+/* update Intel format EIP from host format IP
+ * Note we only mask to 16 bits if the original EIP was 16bits so that
+ * pigger scripts that result in very large EIP values pig correctly.
+ */
+#define UPDATE_INTEL_IP(x) \
+ { int len = DIFF_INST_BYTE(x, p_start); \
+ IU32 mask = 0xFFFFFFFF; \
+ IU32 oldEIP = GET_EIP(); \
+ if ((oldEIP < 0x10000) && (GET_CS_AR_X() == USE16)) \
+ mask = 0xFFFF; \
+ SET_EIP((oldEIP + len) & mask); \
+ }
+
+/* update Intel format EIP from host format IP (mask if 16 operand) */
+#define UPDATE_INTEL_IP_USE_OP_SIZE(x) \
+ if ( GET_OPERAND_SIZE() == USE16 ) \
+ SET_EIP(GET_EIP() + DIFF_INST_BYTE(x, p_start) & WORD_MASK);\
+ else \
+ SET_EIP(GET_EIP() + DIFF_INST_BYTE(x, p_start));
+
+/* mark host format IP as inoperative */
+#define CANCEL_HOST_IP() \
+ quick_mode = FALSE; \
+ p_start = p = (IU8 *)0;
+
+/* setup host format IP from Intel format IP */
+/* and set up end of page marker */
+#ifdef PIG
+#define SETUP_HOST_IP(x) \
+ ip_phy_addr = usr_chk_byte(GET_CS_BASE() + GET_EIP(), PG_R) & SasWrapMask; \
+ x = Sas.SasPtrToPhysAddrByte(ip_phy_addr); \
+ pg_end = AddCpuPtrLS8(CeilingIntelPageLS8(x), 1);
+#else /* !PIG */
+GLOBAL UTINY *CCPU_M;
+#ifdef BACK_M
+#define SETUP_HOST_IP(x) \
+ ip_phy_addr = usr_chk_byte(GET_CS_BASE() + GET_EIP(), PG_R) & \
+ SasWrapMask; \
+ x = &CCPU_M[-ip_phy_addr]; \
+ ip_phy_addr = (ip_phy_addr & ~0xfff) + 0x1000; \
+ pg_end = &CCPU_M[-ip_phy_addr];
+#else
+#define SETUP_HOST_IP(x) \
+ ip_phy_addr = usr_chk_byte(GET_CS_BASE() + GET_EIP(), PG_R) & \
+ SasWrapMask; \
+ x = &CCPU_M[ip_phy_addr]; \
+ ip_phy_addr = (ip_phy_addr & ~0xfff) + 0x1000; \
+ pg_end = &CCPU_M[ip_phy_addr];
+#endif /* BACK_M */
+#endif /* PIG */
+
+GLOBAL INT m_seg[3]; /* Memory Operand segment reg. index. */
+GLOBAL ULONG m_off[3]; /* Memory Operand offset. */
+GLOBAL ULONG m_la[3]; /* Memory Operand Linear Addr. */
+GLOBAL ULONG m_pa[3]; /* Memory Operand Physical Addr. */
+GLOBAL UTINY modRM; /* The modRM byte. */
+GLOBAL UTINY segment_override; /* Segment Prefix for current inst. */
+GLOBAL UTINY *p; /* Pntr. to Intel Opcode Stream. */
+GLOBAL BOOL m_isreg[3]; /* Memory Operand Register(true)/
+ Memory(false) indicator */
+GLOBAL OPERAND ops[3]; /* Inst. Operands. */
+GLOBAL ULONG save_id[3]; /* Saved state for Inst. Operands. */
+GLOBAL ULONG m_la2[3]; /* Memory Operand(2) Linear Addr. */
+GLOBAL ULONG m_pa2[3]; /* Memory Operand(2) Physical Addr. */
+
+#if defined(PIG) && defined(SFELLOW)
+/*
+ * memory-mapped I/O information. Counts number of memory-mapped inputs and
+ * outputs since the last pig synch.
+ */
+GLOBAL struct pig_mmio_info pig_mmio_info;
+
+#endif /* PIG && SFELLOW */
+
+extern void InitNpx IPT1(IBOOL, disable);
+
+/*
+ =====================================================================
+ INTERNAL FUNCTIONS START HERE.
+ =====================================================================
+ */
+
+/*
+ * invalidFunction
+ *
+ * This function will get called if we try to call through the wrong instruction
+ * pointer.
+ */
+
+LOCAL VOID
+invalidFunction IFN0()
+{
+ always_trace0("Invalid Instruction Function Pointer");
+ force_yoda();
+}
+
+/*
+ * note_486_instruction
+ *
+ * This function will get called if we execute a 486-only instruction
+ */
+
+GLOBAL VOID
+note_486_instruction IFN1(char *, text)
+{
+ SAVED IBOOL first = TRUE;
+ SAVED IBOOL want_yoda;
+ SAVED IBOOL want_trace;
+
+ if (first)
+ {
+ char *env = getenv("NOTE_486_INSTRUCTION");
+
+ if (env)
+ {
+ want_yoda = FALSE;
+ want_trace = TRUE;
+ if (strcmp(env, "YODA") == 0)
+ {
+ want_yoda = TRUE;
+ want_trace = TRUE;
+ }
+ if (strcmp(env, "FALSE") == 0)
+ want_trace = FALSE;
+ if (strcmp(env, "TRUE") == 0)
+ want_trace = TRUE;
+ }
+ first = FALSE;
+ }
+ if (want_trace)
+ always_trace0(text);
+ if (want_yoda)
+ force_yoda();
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+/* Internal entry point to CPU. */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+LOCAL VOID
+ccpu
+
+IFN1(
+ ISM32, single_step
+ )
+
+
+ {
+ /* Decoding variables */
+ IU8 opcode; /* Last Opcode Byte Read. */
+
+ /*
+ * A set of function pointers used for pointing to the instruction
+ * emmulation function for the current instruction. We have different
+ * ones because they need to be of different types.
+ *
+ * The name encoding uses 32, 16, or 8 for the size of the parameters,
+ * preceded by a p if it is a pointer. If the parameter string is preceded
+ * by a 2, then this is the second function required by some instructions.
+ *
+ * For safety, these are all set to point at invalidFunction() at the start
+ * of each instruction.
+ */
+
+ VOID (*inst32) IPT1(IU32, op1);
+ VOID (*instp32) IPT1(IU32 *, pop1);
+ VOID (*instp328) IPT2(IU32 *, pop1, IUM8, op_sz);
+ VOID (*instp3232) IPT2(IU32 *, pop1, IU32, op2);
+ VOID (*instp32p32) IPT2(IU32 *, pop1, IU32 *, pop2);
+ VOID (*inst32328) IPT3(IU32, op1, IU32, op2, IUM8, op_sz);
+ VOID (*instp32328) IPT3(IU32 *, pop1, IU32, op2, IUM8, op_sz);
+ VOID (*instp3232328) IPT4(IU32 *, pop1, IU32, op2, IU32, op3, IUM8, op_sz);
+
+ VOID (*inst232) IPT1(IU32, op1);
+ VOID (*inst2p32) IPT1(IU32 *, pop1);
+ VOID (*inst2p3232) IPT2(IU32 *, pop1, IU32, op2);
+
+ /* Operand State variables */
+
+ /* Prefix handling variables */
+ IU8 repeat; /* Repeat Prefix for current inst. */
+ IU32 rep_count; /* Repeat Count for string insts. */
+
+ /* General CPU variables */
+ IU32 ip_phy_addr; /* Used when setting up IP */
+
+ /* Working variables */
+ IU32 immed; /* For immediate generation. */
+
+ ISM32 i;
+ /*
+ Initialise. ----------------------------------------------------
+ */
+
+ single_instruction_delay = FALSE;
+ took_relative_jump = FALSE;
+ took_absolute_toc = FALSE;
+#ifdef PIG
+ pig_synch_required = FALSE;
+#if defined(SFELLOW)
+ pig_mmio_info.flags &= ~(MM_INPUT_OCCURRED | MM_OUTPUT_OCCURRED);
+#endif /* SFELLOW */
+#endif /* PIG */
+
+ /* somewhere for exceptions to return to */
+#ifdef NTVDM
+ setjmp(ccpu386ThrdExptnPtr());
+#else
+ setjmp(next_inst[simulate_level-1]);
+#endif
+
+#ifdef SYNCH_TIMERS
+ /* If we have taken a fault the EDL Cpu will have checked on
+ * the resulting transfer of control.
+ */
+ if (took_absolute_toc || took_relative_jump)
+ goto CHECK_INTERRUPT;
+ quick_mode = TRUE;
+#else /* SYNCH_TIMERS */
+ /* go slow until we are sure we can go fast */
+ quick_mode = FALSE;
+#endif /* SYNCH_TIMERS */
+
+ goto NEXT_INST;
+
+DO_INST:
+
+
+ /* INSIGNIA debugging */
+#ifdef PIG
+ /* We do not want to do check_I() in both CPUs */
+#else /* PIG */
+ if ( do_condition_checks )
+ {
+ check_I();
+ CCPU_save_EIP = GET_EIP(); /* in case yoda changed IP */
+ }
+#endif /* !PIG */
+
+#ifdef PIG
+ save_last_inst_details(NULL);
+ prefix_length = 0;
+#endif
+
+ QUICK_EVENT_TICK();
+
+ /* save beginning of the current instruction */
+
+ p_start = p;
+
+ /*
+ Decode instruction. --------------------------------------------
+ */
+
+ /* 'zero' all prefix byte indicators */
+ segment_override = SEG_CLR;
+ repeat = REP_CLR;
+
+ /*
+ Decode and Action instruction.
+ */
+DECODE:
+
+ opcode = GET_INST_BYTE(p); /* get next byte */
+ /*
+ NB. Each opcode is categorised by a type, instruction name
+ and operand names. The type and operand names are explained
+ further in c_oprnd.h.
+ */
+ switch ( opcode )
+ {
+ case 0x00: /* T5 ADD Eb Gb */
+ instp32328 = ADD;
+TYPE00:
+
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, RW0, PG_W);
+ D_Gb(1);
+ F_Eb(0);
+ F_Gb(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Eb(0);
+ break;
+
+ case 0x01: /* T5 ADD Ev Gv */
+ instp32328 = ADD;
+TYPE01:
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0x02: /* T5 ADD Gb Eb */
+ instp32328 = ADD;
+TYPE02:
+
+ modRM = GET_INST_BYTE(p);
+ D_Gb(0);
+ D_Eb(1, RO1, PG_R);
+ F_Gb(0);
+ F_Eb(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Gb(0);
+ break;
+
+ case 0x03: /* T5 ADD Gv Ev */
+ instp32328 = ADD;
+TYPE03:
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ew(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ed(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Gd(0);
+ }
+ break;
+
+ case 0x04: /* T5 ADD Fal Ib */
+ instp32328 = ADD;
+TYPE04:
+
+ D_Ib(1);
+ F_Fal(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Fal(0);
+ break;
+
+ case 0x05: /* T5 ADD F(e)ax Iv */
+ instp32328 = ADD;
+TYPE05:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Iw(1);
+ F_Fax(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Fax(0);
+ }
+ else /* USE32 */
+ {
+ D_Id(1);
+ F_Feax(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Feax(0);
+ }
+ break;
+
+ case 0x06: /* T2 PUSH Pw */
+ case 0x0e:
+ case 0x16:
+ case 0x1e:
+ D_Pw(0);
+ F_Pw(0);
+ PUSH_SR(ops[0].sng);
+ break;
+
+ case 0x07: /* T3 POP Pw */
+ case 0x17:
+ case 0x1f:
+ D_Pw(0);
+ POP_SR(ops[0].sng);
+ if ( ops[0].sng == SS_REG )
+ {
+ /* locally update IP - interrupts are supressed after POP SS */
+ UPDATE_INTEL_IP(p);
+
+ goto NEXT_INST;
+ }
+ break;
+
+ case 0x08: /* T5 OR Eb Gb */ instp32328 = OR; goto TYPE00;
+ case 0x09: /* T5 OR Ev Gv */ instp32328 = OR; goto TYPE01;
+ case 0x0a: /* T5 OR Gb Eb */ instp32328 = OR; goto TYPE02;
+ case 0x0b: /* T5 OR Gv Ev */ instp32328 = OR; goto TYPE03;
+ case 0x0c: /* T5 OR Fal Ib */ instp32328 = OR; goto TYPE04;
+ case 0x0d: /* T5 OR F(e)ax Iv */ instp32328 = OR; goto TYPE05;
+
+ case 0x0f:
+ opcode = GET_INST_BYTE(p); /* get next opcode byte */
+
+ /* Remove Empty Top of Table here. */
+ if ( opcode >= 0xd0 )
+ Int6();
+
+ switch ( opcode )
+ {
+ case 0x00:
+ if ( GET_PE() == 0 || GET_VM() == 1 )
+ Int6();
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T3 SLDT Ew */
+ instp32 = SLDT;
+TYPE0F00_0:
+
+ D_Ew(0, WO0, PG_W);
+ (*instp32)(&ops[0].sng);
+ P_Ew(0);
+ break;
+
+ case 1: /* T3 STR Ew */ instp32 = STR; goto TYPE0F00_0;
+
+ case 2: /* T2 LLDT Ew */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_LLDT_ACCESS);
+ inst32 = LLDT;
+TYPE0F00_2:
+
+ D_Ew(0, RO0, PG_R);
+ F_Ew(0);
+ (*inst32)(ops[0].sng);
+ break;
+
+ case 3: /* T2 LTR Ew */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_LTR_ACCESS);
+ inst32 = LTR;
+ goto TYPE0F00_2;
+
+ case 4: /* T2 VERR Ew */ inst32 = VERR; goto TYPE0F00_2;
+ case 5: /* T2 VERW Ew */ inst32 = VERW; goto TYPE0F00_2;
+
+ case 6: case 7:
+
+ Int6();
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x01:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T3 SGDT Ms */
+ instp32 = SGDT16;
+ inst2p32 = SGDT32;
+TYPE0F01_0:
+
+ if ( GET_MODE(modRM) == 3 )
+ Int6(); /* Register operand not allowed */
+
+ D_Ms(0, WO0, PG_W);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ (*instp32)(ops[0].mlt);
+ }
+ else /* USE32 */
+ {
+ (*inst2p32)(ops[0].mlt);
+ }
+ P_Ms(0);
+ break;
+
+ case 1: /* T3 SIDT Ms */
+ instp32 = SIDT16;
+ inst2p32 = SIDT32;
+ goto TYPE0F01_0;
+
+ case 2: /* T2 LGDT Ms */
+ instp32 = LGDT16;
+ inst2p32 = LGDT32;
+TYPE0F01_2:
+
+ if ( GET_MODE(modRM) == 3 )
+ Int6(); /* Register operand not allowed */
+
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_LGDT_ACCESS);
+
+ D_Ms(0, RO0, PG_R);
+ F_Ms(0);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ (*instp32)(ops[0].mlt);
+ }
+ else /* USE32 */
+ {
+ (*inst2p32)(ops[0].mlt);
+ }
+ break;
+
+ case 3: /* T2 LIDT Ms */
+ instp32 = LIDT16;
+ inst2p32 = LIDT32;
+ goto TYPE0F01_2;
+
+ case 4: /* T3 SMSW Ew */
+ instp32 = SMSW;
+ goto TYPE0F00_0;
+
+ case 5:
+ Int6();
+ break;
+
+ case 6: /* T2 LMSW Ew */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_LMSW_ACCESS);
+ inst32 = LMSW;
+ goto TYPE0F00_2;
+
+ case 7: /* T2 INVLPG Mm */
+
+#ifdef SPC486
+ note_486_instruction("INVLPG");
+
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_INVLPG_ACCESS);
+ D_Mm(0);
+ F_Mm(0);
+ INVLPG(ops[0].sng);
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x02: /* T5 LAR Gv Ew */
+ instp3232 = LAR;
+TYPE0F02:
+
+ if ( GET_PE() == 0 || GET_VM() == 1 )
+ Int6();
+ modRM = GET_INST_BYTE(p);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ew(1);
+ (*instp3232)(&ops[0].sng, ops[1].sng);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ew(1);
+ (*instp3232)(&ops[0].sng, ops[1].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0x03: /* T5 LSL Gv Ew */
+ instp3232 = LSL;
+ goto TYPE0F02;
+
+ case 0x04: case 0x05: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e:
+
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+
+ case 0x25: case 0x27:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b:
+ case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+
+ case 0x40: case 0x41: case 0x42: case 0x43:
+ case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+
+ case 0xae: case 0xb8: case 0xb9:
+
+ case 0xc2: case 0xc3: case 0xc4: case 0xc5:
+ case 0xc6: case 0xc7:
+ Int6();
+ break;
+
+ case 0xa2:
+ /* Pentium CPUID instruction */
+ note_486_instruction("CPUID");
+ Int6();
+ break;
+
+ case 0xa6: case 0xa7:
+ /* 386, A-Step archaic instruction */
+ note_486_instruction("A-step CMPXCHG");
+ Int6();
+ break;
+
+ case 0xaa:
+ /* Pentium RSM instruction, used by Windows95 */
+ note_486_instruction("RSM");
+ RSRVD();
+ break;
+
+ case 0x06: /* T0 CLTS */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_CLTS_ACCESS);
+ CLTS();
+ break;
+
+ case 0x07: /* T0 "RESERVED" */
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ RSRVD();
+ break;
+
+ case 0x08: /* T0 INVD */
+
+#ifdef SPC486
+ note_486_instruction("INVD");
+
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_INVD_ACCESS);
+ INVD();
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0x09: /* T0 WBINVD */
+
+#ifdef SPC486
+ note_486_instruction("WBINVD");
+
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_WBIND_ACCESS);
+ WBINVD();
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0x0f:
+#ifdef PIG
+ SET_EIP(CCPU_save_EIP);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_NO_EXEC);
+#else
+ Int6();
+#endif /* PIG */
+ break;
+
+ case 0x20: /* T4 MOV Rd Cd */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_R_C_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Rd(0);
+ D_Cd(1);
+ F_Cd(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Rd(0);
+ break;
+
+ case 0x21: /* T4 MOV Rd Dd */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_R_D_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Rd(0);
+ D_Dd(1);
+ F_Dd(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Rd(0);
+ break;
+
+ case 0x22: /* T4 MOV Cd Rd */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_C_R_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Cd(0);
+ D_Rd(1);
+ F_Rd(1);
+ MOV_CR(ops[0].sng, ops[1].sng);
+ break;
+
+ case 0x23: /* T4 MOV Dd Rd */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_D_R_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Dd(0);
+ D_Rd(1);
+ F_Rd(1);
+ MOV_DR(ops[0].sng, ops[1].sng);
+ quick_mode = FALSE;
+ break;
+
+ case 0x24: /* T4 MOV Rd Td */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_R_T_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Rd(0);
+ D_Td(1);
+ F_Td(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Rd(0);
+ break;
+
+ case 0x26: /* T4 MOV Td Rd */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_MOV_T_R_ACCESS);
+ modRM = GET_INST_BYTE(p);
+ D_Td(0);
+ D_Rd(1);
+ F_Rd(1);
+ MOV_TR(ops[0].sng, ops[1].sng);
+ break;
+
+ case 0x80: /* T2 JO Jv */
+ inst32 = JO;
+TYPE0F80:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Jw(0);
+ }
+ else
+ {
+ D_Jd(0);
+ }
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+#ifdef SYNCH_BOTH_WAYS
+ took_relative_jump = TRUE;
+#endif /* SYNCH_BOTH_WAYS */
+ if (took_relative_jump)
+ {
+ PIG_SYNCH(CHECK_ALL);
+ }
+ break;
+
+ case 0x81: /* T2 JNO Jv */ inst32 = JNO; goto TYPE0F80;
+ case 0x82: /* T2 JB Jv */ inst32 = JB; goto TYPE0F80;
+ case 0x83: /* T2 JNB Jv */ inst32 = JNB; goto TYPE0F80;
+ case 0x84: /* T2 JZ Jv */ inst32 = JZ; goto TYPE0F80;
+ case 0x85: /* T2 JNZ Jv */ inst32 = JNZ; goto TYPE0F80;
+ case 0x86: /* T2 JBE Jv */ inst32 = JBE; goto TYPE0F80;
+ case 0x87: /* T2 JNBE Jv */ inst32 = JNBE; goto TYPE0F80;
+ case 0x88: /* T2 JS Jv */ inst32 = JS; goto TYPE0F80;
+ case 0x89: /* T2 JNS Jv */ inst32 = JNS; goto TYPE0F80;
+ case 0x8a: /* T2 JP Jv */ inst32 = JP; goto TYPE0F80;
+ case 0x8b: /* T2 JNP Jv */ inst32 = JNP; goto TYPE0F80;
+ case 0x8c: /* T2 JL Jv */ inst32 = JL; goto TYPE0F80;
+ case 0x8d: /* T2 JNL Jv */ inst32 = JNL; goto TYPE0F80;
+ case 0x8e: /* T2 JLE Jv */ inst32 = JLE; goto TYPE0F80;
+ case 0x8f: /* T2 JNLE Jv */ inst32 = JNLE; goto TYPE0F80;
+
+ case 0x90: /* T3 SETO Eb */
+ instp32 = SETO;
+TYPE0F90:
+
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, WO0, PG_W);
+ (*instp32)(&ops[0].sng);
+ P_Eb(0);
+ break;
+
+ case 0x91: /* T3 SETNO Eb */ instp32 = SETNO; goto TYPE0F90;
+ case 0x92: /* T3 SETB Eb */ instp32 = SETB; goto TYPE0F90;
+ case 0x93: /* T3 SETNB Eb */ instp32 = SETNB; goto TYPE0F90;
+ case 0x94: /* T3 SETZ Eb */ instp32 = SETZ; goto TYPE0F90;
+ case 0x95: /* T3 SETNZ Eb */ instp32 = SETNZ; goto TYPE0F90;
+ case 0x96: /* T3 SETBE Eb */ instp32 = SETBE; goto TYPE0F90;
+ case 0x97: /* T3 SETNBE Eb */ instp32 = SETNBE; goto TYPE0F90;
+ case 0x98: /* T3 SETS Eb */ instp32 = SETS; goto TYPE0F90;
+ case 0x99: /* T3 SETNS Eb */ instp32 = SETNS; goto TYPE0F90;
+ case 0x9a: /* T3 SETP Eb */ instp32 = SETP; goto TYPE0F90;
+ case 0x9b: /* T3 SETNP Eb */ instp32 = SETNP; goto TYPE0F90;
+ case 0x9c: /* T3 SETL Eb */ instp32 = SETL; goto TYPE0F90;
+ case 0x9d: /* T3 SETNL Eb */ instp32 = SETNL; goto TYPE0F90;
+ case 0x9e: /* T3 SETLE Eb */ instp32 = SETLE; goto TYPE0F90;
+ case 0x9f: /* T3 SETNLE Eb */ instp32 = SETNLE; goto TYPE0F90;
+
+ case 0xa0: /* T2 PUSH Qw */
+ case 0xa8:
+ D_Qw(0);
+ F_Qw(0);
+ PUSH_SR(ops[0].sng);
+ break;
+
+ case 0xa1: /* T3 POP Qw */
+ case 0xa9:
+ D_Qw(0);
+ POP_SR(ops[0].sng);
+ break;
+
+ case 0xa3: /* T6 BT Ev Gv */
+ inst32328 = BT;
+#ifndef FIX_BT_BUG
+ goto TYPE39;
+#endif
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ BT_OPSw(RO0, PG_R);
+ (*inst32328)(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ BT_OPSd(RO0, PG_R);
+ (*inst32328)(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+
+ case 0xa4: /* T9 SHLD Ev Gv Ib */
+ instp3232328 = SHLD;
+TYPE0FA4:
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ D_Ib(2);
+ F_Ew(0);
+ F_Gw(1);
+ (*instp3232328)(&ops[0].sng, ops[1].sng, ops[2].sng, 16);
+ P_Ew(0);
+ }
+ else
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ D_Ib(2);
+ F_Ed(0);
+ F_Gd(1);
+ (*instp3232328)(&ops[0].sng, ops[1].sng, ops[2].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xa5: /* T9 SHLD Ev Gv Fcl */
+ instp3232328 = SHLD;
+TYPE0FA5:
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ F_Fcl(2);
+ (*instp3232328)(&ops[0].sng, ops[1].sng, ops[2].sng, 16);
+ P_Ew(0);
+ }
+ else
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ F_Fcl(2);
+ (*instp3232328)(&ops[0].sng, ops[1].sng, ops[2].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xab: /* T5 BTS Ev Gv */
+ instp32328 = BTS;
+#ifndef FIX_BT_BUG
+ goto TYPE01;
+#endif
+TYPE0FAB:
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ BT_OPSw(RW0, PG_W);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ BT_OPSd(RW0, PG_W);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xac: /* T9 SHRD Ev Gv Ib */
+ instp3232328 = SHRD;
+ goto TYPE0FA4;
+
+ case 0xad: /* T9 SHRD Ev Gv Fcl */
+ instp3232328 = SHRD;
+ goto TYPE0FA5;
+
+ case 0xaf: /* T5 IMUL Gv Ev */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ew(1);
+ IMUL16T(&ops[0].sng, ops[0].sng, ops[1].sng);
+ P_Gw(0);
+ }
+ else
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ed(1);
+ IMUL32T(&ops[0].sng, ops[0].sng, ops[1].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0xb0: /* T5 CMPXCHG Eb Gb */
+
+#ifdef SPC486
+ note_486_instruction("CMPXCHG Eb Gb");
+
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, RW0, PG_W);
+ D_Gb(1);
+ F_Eb(0);
+ F_Gb(1);
+ CMPXCHG8(&ops[0].sng, ops[1].sng);
+ P_Eb(0);
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0xb1: /* T5 CMPXCHG Ev Gv */
+
+#ifdef SPC486
+ note_486_instruction("CMPXCHG Ev Gv");
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ CMPXCHG16(&ops[0].sng, ops[1].sng);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ CMPXCHG32(&ops[0].sng, ops[1].sng);
+ P_Ed(0);
+ }
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0xb2: /* T4 LSS Gv Mp */ instp32p32 = LSS; goto TYPEC4;
+#ifndef FIX_BT_BUG
+ case 0xb3: /* T5 BTR Ev Gv */ instp32328 = BTR; goto TYPE01;
+#else
+ case 0xb3: /* T5 BTR Ev Gv */ instp32328 = BTR; goto TYPE0FAB;
+#endif
+ case 0xb4: /* T4 LFS Gv Mp */ instp32p32 = LFS; goto TYPEC4;
+ case 0xb5: /* T4 LGS Gv Mp */ instp32p32 = LGS; goto TYPEC4;
+
+ case 0xb6: /* T4 MOVZX Gv Eb */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Eb(1, RO1, PG_R);
+ F_Eb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gw(0);
+ }
+ else
+ {
+ D_Gd(0);
+ D_Eb(1, RO1, PG_R);
+ F_Eb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gd(0);
+ }
+ break;
+
+ case 0xb7: /* T4 MOVZX Gd Ew */
+ modRM = GET_INST_BYTE(p);
+ D_Gd(0);
+ D_Ew(1, RO1, PG_R);
+ F_Ew(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gd(0);
+ break;
+
+ case 0xba:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: case 1: case 2: case 3:
+ Int6();
+ break;
+
+ case 4: /* T6 BT Ev Ib */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ D_Ib(1);
+ F_Ew(0);
+ BT(ops[0].sng, ops[1].sng, 16);
+ }
+ else
+ {
+ D_Ed(0, RO0, PG_R);
+ D_Ib(1);
+ F_Ed(0);
+ BT(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+
+ case 5: /* T5 BTS Ev Ib */ instp32328 = BTS; goto TYPEC1;
+ case 6: /* T5 BTR Ev Ib */ instp32328 = BTR; goto TYPEC1;
+ case 7: /* T5 BTC Ev Ib */ instp32328 = BTC; goto TYPEC1;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0xbb: /* T5 BTC Ev Gv */
+ instp32328 = BTC;
+#ifndef FIX_BT_BUG
+ goto TYPE01;
+#else
+ goto TYPE0FAB;
+#endif
+ case 0xbc: /* T5 BSF Gv Ev */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ew(1);
+ BSF(&ops[0].sng, ops[1].sng);
+ P_Gw(0);
+ }
+ else
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ed(1);
+ BSF(&ops[0].sng, ops[1].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0xbd: /* T5 BSR Gv Ev */
+ instp32328 = BSR;
+ goto TYPE03;
+
+ case 0xbe: /* T4 MOVSX Gv Eb */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Eb(1, RO1, PG_R);
+ F_Eb(1);
+ MOVSX(&ops[0].sng, ops[1].sng, 8);
+ P_Gw(0);
+ }
+ else
+ {
+ D_Gd(0);
+ D_Eb(1, RO1, PG_R);
+ F_Eb(1);
+ MOVSX(&ops[0].sng, ops[1].sng, 8);
+ P_Gd(0);
+ }
+ break;
+
+ case 0xbf: /* T4 MOVSX Gd Ew */
+ modRM = GET_INST_BYTE(p);
+ D_Gd(0);
+ D_Ew(1, RO1, PG_R);
+ F_Ew(1);
+ MOVSX(&ops[0].sng, ops[1].sng, 16);
+ P_Gd(0);
+ break;
+
+ case 0xc0: /* T8 XADD Eb Gb */
+
+#ifdef SPC486
+ note_486_instruction("XADD Eb Gb");
+
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, RW0, PG_W);
+ D_Gb(1);
+ F_Eb(0);
+ F_Gb(1);
+ XADD(&ops[0].sng, &ops[1].sng, 8);
+ P_Eb(0);
+ P_Gb(1);
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0xc1: /* T8 XADD Ev Gv */
+
+#ifdef SPC486
+ note_486_instruction("XADD Ev Gv");
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ XADD(&ops[0].sng, &ops[1].sng, 16);
+ P_Ew(0);
+ P_Gw(1);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ XADD(&ops[0].sng, &ops[1].sng, 32);
+ P_Ed(0);
+ P_Gd(1);
+ }
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+
+ case 0xc8: /* T1 BSWAP Hv */
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+
+#ifdef SPC486
+ note_486_instruction("BSWAP Hv");
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Hd(0); /* BSWAP 16 bit reads 32 bit & writes 16 */
+ F_Hd(0); /* so getting EAX -> EAX' -> AX */
+ BSWAP(&ops[0].sng);
+ P_Hw(0);
+ }
+ else /* USE32 */
+ {
+ D_Hd(0);
+ F_Hd(0);
+ BSWAP(&ops[0].sng);
+ P_Hd(0);
+ }
+#else
+ Int6();
+#endif /* SPC486 */
+
+ break;
+ } /* end switch ( opcode ) 0F */
+ break;
+
+ case 0x10: /* T5 ADC Eb Gb */ instp32328 = ADC; goto TYPE00;
+ case 0x11: /* T5 ADC Ev Gv */ instp32328 = ADC; goto TYPE01;
+ case 0x12: /* T5 ADC Gb Eb */ instp32328 = ADC; goto TYPE02;
+ case 0x13: /* T5 ADC Gv Ev */ instp32328 = ADC; goto TYPE03;
+ case 0x14: /* T5 ADC Fal Ib */ instp32328 = ADC; goto TYPE04;
+ case 0x15: /* T5 ADC F(e)ax Iv */ instp32328 = ADC; goto TYPE05;
+
+ case 0x18: /* T5 SBB Eb Gb */ instp32328 = SBB; goto TYPE00;
+ case 0x19: /* T5 SBB Ev Gv */ instp32328 = SBB; goto TYPE01;
+ case 0x1a: /* T5 SBB Gb Eb */ instp32328 = SBB; goto TYPE02;
+ case 0x1b: /* T5 SBB Gv Ev */ instp32328 = SBB; goto TYPE03;
+ case 0x1c: /* T5 SBB Fal Ib */ instp32328 = SBB; goto TYPE04;
+ case 0x1d: /* T5 SBB F(e)ax Iv */ instp32328 = SBB; goto TYPE05;
+
+ case 0x20: /* T5 AND Eb Gb */ instp32328 = AND; goto TYPE00;
+ case 0x21: /* T5 AND Ev Gv */ instp32328 = AND; goto TYPE01;
+ case 0x22: /* T5 AND Gb Eb */ instp32328 = AND; goto TYPE02;
+ case 0x23: /* T5 AND Gb Eb */ instp32328 = AND; goto TYPE03;
+ case 0x24: /* T5 AND Fal Ib */ instp32328 = AND; goto TYPE04;
+ case 0x25: /* T5 AND F(e)ax Iv */ instp32328 = AND; goto TYPE05;
+
+ case 0x26:
+ segment_override = ES_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x27: /* T0 DAA */
+ DAA();
+ break;
+
+ case 0x28: /* T5 SUB Eb Gb */ instp32328 = SUB; goto TYPE00;
+ case 0x29: /* T5 SUB Ev Gv */ instp32328 = SUB; goto TYPE01;
+ case 0x2a: /* T5 SUB Gb Eb */ instp32328 = SUB; goto TYPE02;
+ case 0x2b: /* T5 SUB Gv Ev */ instp32328 = SUB; goto TYPE03;
+ case 0x2c: /* T5 SUB Fal Ib */ instp32328 = SUB; goto TYPE04;
+ case 0x2d: /* T5 SUB F(e)ax Iv */ instp32328 = SUB; goto TYPE05;
+
+ case 0x2e:
+ segment_override = CS_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x2f: /* T0 DAS */
+ DAS();
+ break;
+
+ case 0x30: /* T5 XOR Eb Gb */ instp32328 = XOR; goto TYPE00;
+ case 0x31: /* T5 XOR Ev Gv */ instp32328 = XOR; goto TYPE01;
+ case 0x32: /* T5 XOR Gb Eb */ instp32328 = XOR; goto TYPE02;
+ case 0x33: /* T5 XOR Gv Ev */ instp32328 = XOR; goto TYPE03;
+ case 0x34: /* T5 XOR Fal Ib */ instp32328 = XOR; goto TYPE04;
+ case 0x35: /* T5 XOR F(e)ax Iv */ instp32328 = XOR; goto TYPE05;
+
+ case 0x36:
+ segment_override = SS_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x37: /* T0 AAA */
+ AAA();
+ break;
+
+ case 0x38: /* T6 CMP Eb Gb */
+ inst32328 = CMP;
+TYPE38:
+
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, RO0, PG_R);
+ D_Gb(1);
+ F_Eb(0);
+ F_Gb(1);
+ (*inst32328)(ops[0].sng, ops[1].sng, 8);
+ break;
+
+ case 0x39: /* T6 CMP Ev Gv */
+ inst32328 = CMP;
+TYPE39:
+
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ (*inst32328)(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RO0, PG_R);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ (*inst32328)(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+
+ case 0x3a: /* T6 CMP Gb Eb */
+ modRM = GET_INST_BYTE(p);
+ D_Gb(0);
+ D_Eb(1, RO1, PG_R);
+ F_Gb(0);
+ F_Eb(1);
+ CMP(ops[0].sng, ops[1].sng, 8);
+ break;
+
+ case 0x3b: /* T6 CMP Gv Ev */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ew(1);
+ CMP(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ed(1);
+ CMP(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+
+ case 0x3c: /* T6 CMP Fal Ib */
+ inst32328 = CMP;
+TYPE3C:
+
+ D_Ib(1);
+ F_Fal(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 8);
+ break;
+
+ case 0x3d: /* T6 CMP F(e)ax Iv */
+ inst32328 = CMP;
+TYPE3D:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Iw(1);
+ F_Fax(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ D_Id(1);
+ F_Feax(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+
+ case 0x3e:
+ segment_override = DS_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x3f: /* T0 AAS */
+ AAS();
+ break;
+
+ case 0x40: /* T1 INC Hv */
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ instp328 = INC;
+TYPE40:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Hw(0);
+ F_Hw(0);
+ (*instp328)(&ops[0].sng, 16);
+ P_Hw(0);
+ }
+ else /* USE32 */
+ {
+ D_Hd(0);
+ F_Hd(0);
+ (*instp328)(&ops[0].sng, 32);
+ P_Hd(0);
+ }
+ break;
+
+ case 0x48: /* T1 DEC Hv */
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ instp328 = DEC;
+ goto TYPE40;
+
+ case 0x50: /* T2 PUSH Hv */
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Hw(0);
+ F_Hw(0);
+ }
+ else /* USE32 */
+ {
+ D_Hd(0);
+ F_Hd(0);
+ }
+ PUSH(ops[0].sng);
+ break;
+
+ case 0x58: /* T3 POP Hv */
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Hw(0);
+ POP(&ops[0].sng);
+ P_Hw(0);
+ }
+ else /* USE32 */
+ {
+ D_Hd(0);
+ POP(&ops[0].sng);
+ P_Hd(0);
+ }
+ break;
+
+ case 0x60: /* T0 PUSHA */
+ PUSHA();
+ break;
+
+ case 0x61: /* T0 POPA */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ POPA();
+ }
+ else /* USE32 */
+ {
+ POPAD();
+ }
+ break;
+
+ case 0x62: /* T6 BOUND Gv Ma */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ma16(1, RO1, PG_R);
+ F_Gw(0);
+ F_Ma16(1);
+ BOUND(ops[0].sng, ops[1].mlt, 16);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ma32(1, RO1, PG_R);
+ F_Gd(0);
+ F_Ma32(1);
+ BOUND(ops[0].sng, ops[1].mlt, 32);
+ }
+ break;
+
+ case 0x63: /* T5 ARPL Ew Gw */
+ if ( GET_PE() == 0 || GET_VM() == 1 )
+ Int6();
+ modRM = GET_INST_BYTE(p);
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ ARPL(&ops[0].sng, ops[1].sng);
+ P_Ew(0);
+ break;
+
+ case 0x64:
+ segment_override = FS_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x65:
+ segment_override = GS_REG;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x66:
+ SET_OPERAND_SIZE(GET_CS_AR_X());
+ if ( GET_OPERAND_SIZE() == USE16 )
+ SET_OPERAND_SIZE(USE32);
+ else /* USE32 */
+ SET_OPERAND_SIZE(USE16);
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x67:
+ SET_ADDRESS_SIZE(GET_CS_AR_X());
+ if ( GET_ADDRESS_SIZE() == USE16 )
+ SET_ADDRESS_SIZE(USE32);
+ else /* USE32 */
+ SET_ADDRESS_SIZE(USE16);
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0x68: /* T2 PUSH Iv */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Iw(0);
+ }
+ else /* USE32 */
+ {
+ D_Id(0);
+ }
+ PUSH(ops[0].sng);
+ break;
+
+ case 0x69: /* T7 IMUL Gv Ev Iv */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ D_Iw(2);
+ F_Gw(0);
+ F_Ew(1);
+ IMUL16T(&ops[0].sng, ops[1].sng, ops[2].sng);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ D_Id(2);
+ F_Gd(0);
+ F_Ed(1);
+ IMUL32T(&ops[0].sng, ops[1].sng, ops[2].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0x6a: /* T2 PUSH Ib */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ix(0);
+ }
+ else /* USE32 */
+ {
+ D_Iy(0);
+ }
+ PUSH(ops[0].sng);
+ break;
+
+ case 0x6b: /* T7 IMUL Gv Ev Ib */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ D_Ix(2);
+ F_Gw(0);
+ F_Ew(1);
+ IMUL16T(&ops[0].sng, ops[1].sng, ops[2].sng);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ D_Iy(2);
+ F_Gd(0);
+ F_Ed(1);
+ IMUL32T(&ops[0].sng, ops[1].sng, ops[2].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0x6c: /* T4 INSB Yb Fdx */
+ STRING_COUNT;
+ F_Fdx(1);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, BYTE_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Yb(0, WO0, PG_W);
+ IN8(&ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Yb(0);
+ PIG_P_Yb(0);
+ /*
+ KNOWN BUG #1.
+ We should check for pending interrupts here, at least:-
+ Single step trap
+ Debug trap
+ */
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_SOME_MEM);
+ quick_mode = FALSE;
+ break;
+
+ case 0x6d: /* T4 INSW Yv Fdx */
+ STRING_COUNT;
+ F_Fdx(1);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, WORD_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Yw(0, WO0, PG_W);
+ IN16(&ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Yw(0);
+ PIG_P_Yw(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, DWORD_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Yd(0, WO0, PG_W);
+ IN32(&ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Yd(0);
+ PIG_P_Yd(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_SOME_MEM);
+ quick_mode = FALSE;
+ break;
+
+ case 0x6e: /* T6 OUTSB Fdx Xb */
+ STRING_COUNT;
+ F_Fdx(0);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, BYTE_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Xb(1, RO1, PG_R);
+ F_Xb(1);
+ OUT8(ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Xb(1);
+ /* KNOWN BUG #1. */
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_ALL);
+ quick_mode = FALSE;
+ break;
+
+ case 0x6f: /* T6 OUTSW Fdx Xv */
+ STRING_COUNT;
+ F_Fdx(0);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, WORD_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Xw(1, RO1, PG_R);
+ F_Xw(1);
+ OUT16(ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Xw(1);
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, DWORD_WIDTH);
+
+ while ( rep_count )
+ {
+ D_Xd(1, RO1, PG_R);
+ F_Xd(1);
+ OUT32(ops[0].sng, ops[1].sng);
+ rep_count--;
+ C_Xd(1);
+ /* KNOWN BUG #1. */
+ }
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_ALL);
+ quick_mode = FALSE;
+ break;
+
+ case 0x70: /* T2 JO Jb */
+ inst32 = JO;
+TYPE70:
+
+ D_Jb(0);
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+#ifdef PIG
+ if ((opcode != 0xeb) && (ops[0].sng == 3))
+ {
+ /* Convert the EDL cpu super-instructions
+ *
+ * Jcc .+03
+ * JMPN dst
+ *
+ * into
+ *
+ * Jcc' dest
+ */
+ int offset_in_page = DiffCpuPtrsLS8(FloorIntelPageLS8(p), p);
+
+ if ((GET_CS_AR_X() == 0)
+ && (offset_in_page != 0)
+ && (offset_in_page <= 0xFFD)
+ && (*p == 0xe9))
+ {
+ p_start = p;
+ (void)GET_INST_BYTE(p);
+ switch (opcode)
+ {
+ case 0x70: /* T2 JO Jb */ inst32 = JNO; goto TYPE0F80;
+ case 0x71: /* T2 JNO Jb */ inst32 = JO; goto TYPE0F80;
+ case 0x72: /* T2 JB Jb */ inst32 = JNB; goto TYPE0F80;
+ case 0x73: /* T2 JNB Jb */ inst32 = JB; goto TYPE0F80;
+ case 0x74: /* T2 JZ Jb */ inst32 = JNZ; goto TYPE0F80;
+ case 0x75: /* T2 JNZ Jb */ inst32 = JZ; goto TYPE0F80;
+ case 0x76: /* T2 JBE Jb */ inst32 = JNBE; goto TYPE0F80;
+ case 0x77: /* T2 JNBE Jb */ inst32 = JBE; goto TYPE0F80;
+ case 0x78: /* T2 JS Jb */ inst32 = JNS; goto TYPE0F80;
+ case 0x79: /* T2 JNS Jb */ inst32 = JS; goto TYPE0F80;
+ case 0x7a: /* T2 JP Jb */ inst32 = JNP; goto TYPE0F80;
+ case 0x7b: /* T2 JNP Jb */ inst32 = JP; goto TYPE0F80;
+ case 0x7c: /* T2 JL Jb */ inst32 = JNL; goto TYPE0F80;
+ case 0x7d: /* T2 JNL Jb */ inst32 = JL; goto TYPE0F80;
+ case 0x7e: /* T2 JLE Jb */ inst32 = JNLE; goto TYPE0F80;
+ case 0x7f: /* T2 JNLE Jb */ inst32 = JLE; goto TYPE0F80;
+ default:
+ break;
+ }
+ }
+ }
+#endif /* PIG */
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+
+#ifdef PIG
+ if (single_instruction_delay && !took_relative_jump)
+ {
+ if (single_instruction_delay_enable)
+ {
+ save_last_xcptn_details("STI/POPF blindspot\n", 0, 0, 0, 0, 0);
+ PIG_SYNCH(CHECK_NO_EXEC);
+ }
+ else
+ {
+ save_last_xcptn_details("STI/POPF problem\n", 0, 0, 0, 0, 0);
+ }
+ break;
+ }
+#ifdef SYNCH_BOTH_WAYS
+ took_relative_jump = TRUE;
+#endif /* SYNCH_BOTH_WAYS */
+ if (took_relative_jump)
+ {
+ PIG_SYNCH(CHECK_ALL);
+ }
+#endif /* PIG */
+ break;
+
+ case 0x71: /* T2 JNO Jb */ inst32 = JNO; goto TYPE70;
+ case 0x72: /* T2 JB Jb */ inst32 = JB; goto TYPE70;
+ case 0x73: /* T2 JNB Jb */ inst32 = JNB; goto TYPE70;
+ case 0x74: /* T2 JZ Jb */ inst32 = JZ; goto TYPE70;
+ case 0x75: /* T2 JNZ Jb */ inst32 = JNZ; goto TYPE70;
+ case 0x76: /* T2 JBE Jb */ inst32 = JBE; goto TYPE70;
+ case 0x77: /* T2 JNBE Jb */ inst32 = JNBE; goto TYPE70;
+ case 0x78: /* T2 JS Jb */ inst32 = JS; goto TYPE70;
+ case 0x79: /* T2 JNS Jb */ inst32 = JNS; goto TYPE70;
+ case 0x7a: /* T2 JP Jb */ inst32 = JP; goto TYPE70;
+ case 0x7b: /* T2 JNP Jb */ inst32 = JNP; goto TYPE70;
+ case 0x7c: /* T2 JL Jb */ inst32 = JL; goto TYPE70;
+ case 0x7d: /* T2 JNL Jb */ inst32 = JNL; goto TYPE70;
+ case 0x7e: /* T2 JLE Jb */ inst32 = JLE; goto TYPE70;
+ case 0x7f: /* T2 JNLE Jb */ inst32 = JNLE; goto TYPE70;
+
+ case 0x80:
+ case 0x82:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ADD Eb Ib */
+ instp32328 = ADD;
+TYPE80_0:
+
+ D_Eb(0, RW0, PG_W);
+ D_Ib(1);
+ F_Eb(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Eb(0);
+ break;
+
+ case 1: /* T5 OR Eb Ib */ instp32328 = OR; goto TYPE80_0;
+ case 2: /* T5 ADC Eb Ib */ instp32328 = ADC; goto TYPE80_0;
+ case 3: /* T5 SBB Eb Ib */ instp32328 = SBB; goto TYPE80_0;
+ case 4: /* T5 AND Eb Ib */ instp32328 = AND; goto TYPE80_0;
+ case 5: /* T5 SUB Eb Ib */ instp32328 = SUB; goto TYPE80_0;
+ case 6: /* T5 XOR Eb Ib */ instp32328 = XOR; goto TYPE80_0;
+
+ case 7: /* T6 CMP Eb Ib */
+ inst32328 = CMP;
+TYPE80_7:
+
+ D_Eb(0, RO0, PG_R);
+ D_Ib(1);
+ F_Eb(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 8);
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x81:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ADD Ev Iv */
+ instp32328 = ADD;
+TYPE81_0:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Iw(1);
+ F_Ew(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Id(1);
+ F_Ed(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 1: /* T5 OR Ev Iv */ instp32328 = OR; goto TYPE81_0;
+ case 2: /* T5 ADC Ev Iv */ instp32328 = ADC; goto TYPE81_0;
+ case 3: /* T5 SBB Ev Iv */ instp32328 = SBB; goto TYPE81_0;
+ case 4: /* T5 AND Ev Iv */ instp32328 = AND; goto TYPE81_0;
+ case 5: /* T5 SUB Ev Iv */ instp32328 = SUB; goto TYPE81_0;
+ case 6: /* T5 XOR Ev Iv */ instp32328 = XOR; goto TYPE81_0;
+
+ case 7: /* T6 CMP Ev Iv */
+ inst32328 = CMP;
+TYPE81_7:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ D_Iw(1);
+ F_Ew(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RO0, PG_R);
+ D_Id(1);
+ F_Ed(0);
+ (*inst32328)(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x83:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ADD Ev Ib */
+ instp32328 = ADD;
+TYPE83_0:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Ix(1);
+ F_Ew(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Iy(1);
+ F_Ed(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 1: /* T5 OR Ev Ib */ instp32328 = OR; goto TYPE83_0;
+ case 2: /* T5 ADC Ev Ib */ instp32328 = ADC; goto TYPE83_0;
+ case 3: /* T5 SBB Ev Ib */ instp32328 = SBB; goto TYPE83_0;
+ case 4: /* T5 AND Ev Ib */ instp32328 = AND; goto TYPE83_0;
+ case 5: /* T5 SUB Ev Ib */ instp32328 = SUB; goto TYPE83_0;
+ case 6: /* T5 XOR Ev Ib */ instp32328 = XOR; goto TYPE83_0;
+
+ case 7: /* T6 CMP Ev Ib */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ D_Ix(1);
+ F_Ew(0);
+ CMP(ops[0].sng, ops[1].sng, 16);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RO0, PG_R);
+ D_Iy(1);
+ F_Ed(0);
+ CMP(ops[0].sng, ops[1].sng, 32);
+ }
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x84: /* T6 TEST Eb Gb */ inst32328 = TEST; goto TYPE38;
+ case 0x85: /* T6 TEST Ev Gv */ inst32328 = TEST; goto TYPE39;
+
+ case 0x86: /* T8 XCHG Eb Gb */
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, RW0, PG_W);
+ D_Gb(1);
+ F_Eb(0);
+ F_Gb(1);
+ XCHG(&ops[0].sng, &ops[1].sng);
+ P_Eb(0);
+ P_Gb(1);
+ break;
+
+ case 0x87: /* T8 XCHG Ev Gv */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Gw(1);
+ F_Ew(0);
+ F_Gw(1);
+ XCHG(&ops[0].sng, &ops[1].sng);
+ P_Ew(0);
+ P_Gw(1);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Gd(1);
+ F_Ed(0);
+ F_Gd(1);
+ XCHG(&ops[0].sng, &ops[1].sng);
+ P_Ed(0);
+ P_Gd(1);
+ }
+ break;
+
+ case 0x88: /* T4 MOV Eb Gb */
+ modRM = GET_INST_BYTE(p);
+ D_Eb(0, WO0, PG_W);
+ D_Gb(1);
+ F_Gb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Eb(0);
+ break;
+
+ case 0x89: /* T4 MOV Ev Gv */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, WO0, PG_W);
+ D_Gw(1);
+ F_Gw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, WO0, PG_W);
+ D_Gd(1);
+ F_Gd(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ed(0);
+ }
+ break;
+
+ case 0x8a: /* T4 MOV Gb Eb */
+ modRM = GET_INST_BYTE(p);
+ D_Gb(0);
+ D_Eb(1, RO1, PG_R);
+ F_Eb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gb(0);
+ break;
+
+ case 0x8b: /* T4 MOV Gv Ev */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Ew(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Ed(1, RO1, PG_R);
+ F_Ed(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Gd(0);
+ }
+ break;
+
+ case 0x8c: /* T4 MOV Ew Nw */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_SEG(modRM) > MAX_VALID_SEG )
+ Int6();
+
+ if ( GET_OPERAND_SIZE() == USE16 || modRM < LOWEST_REG_MODRM )
+ {
+ D_Ew(0, WO0, PG_W);
+ D_Nw(1);
+ F_Nw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ew(0);
+ }
+ else /* USE32 and REGISTER */
+ {
+ D_Rd(0);
+ D_Nw(1);
+ F_Nw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Rd(0);
+ }
+ break;
+
+ case 0x8d: /* T4 LEA Gv M */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_M(1);
+ F_M(1);
+ LEA(&ops[0].sng, ops[1].sng);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_M(1);
+ F_M(1);
+ LEA(&ops[0].sng, ops[1].sng);
+ P_Gd(0);
+ }
+ break;
+
+ case 0x8e: /* T4 MOV Nw Ew */
+ modRM = GET_INST_BYTE(p);
+ if ( GET_SEG(modRM) > MAX_VALID_SEG || GET_SEG(modRM) == CS_REG )
+ Int6();
+ D_Nw(0);
+ D_Ew(1, RO1, PG_R);
+ F_Ew(1);
+ MOV_SR(ops[0].sng, ops[1].sng);
+ if ( GET_SEG(modRM) == SS_REG )
+ {
+ /* locally update IP - interrupts are supressed after MOV SS,xx */
+ UPDATE_INTEL_IP(p);
+
+ goto NEXT_INST;
+ }
+ break;
+
+ case 0x8f:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T3 POP Ev */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ SET_POP_DISP(2); /* in case they use [ESP] */
+ D_Ew(0, WO0, PG_W);
+ POP(&ops[0].sng);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ SET_POP_DISP(4); /* in case they use [ESP] */
+ D_Ed(0, WO0, PG_W);
+ POP(&ops[0].sng);
+ P_Ed(0);
+ }
+ SET_POP_DISP(0);
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ Int6();
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0x90: /* T0 NOP */
+ break;
+
+ case 0x91: /* T8 XCHG F(e)ax Hv */
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ F_Fax(0);
+ D_Hw(1);
+ F_Hw(1);
+ XCHG(&ops[0].sng, &ops[1].sng);
+ P_Fax(0);
+ P_Hw(1);
+ }
+ else /* USE32 */
+ {
+ F_Feax(0);
+ D_Hd(1);
+ F_Hd(1);
+ XCHG(&ops[0].sng, &ops[1].sng);
+ P_Feax(0);
+ P_Hd(1);
+ }
+ break;
+
+ case 0x98: /* T0 CBW */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ CBW();
+ }
+ else /* USE32 */
+ {
+ CWDE();
+ }
+ break;
+
+ case 0x99: /* T0 CWD */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ CWD();
+ }
+ else /* USE32 */
+ {
+ CDQ();
+ }
+ break;
+
+ case 0x9a: /* T2 CALL Ap */
+ instp32 = CALLF;
+ took_absolute_toc = TRUE;
+TYPE9A:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Aw(0);
+ }
+ else /* USE32 */
+ {
+ D_Ad(0);
+ }
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*instp32)(ops[0].mlt);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0x9b: /* T0 WAIT */
+ if ( GET_MP() && GET_TS() )
+ Int7();
+ WAIT();
+ break;
+
+ case 0x9c: /* T0 PUSHF */
+ if ( GET_VM() == 1 && GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_PUSHF_ACCESS);
+ PUSHF();
+ break;
+
+ case 0x9d: /* T0 POPF */
+ {
+ int oldIF;
+
+ if ( GET_VM() == 1 && GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_POPF_ACCESS);
+
+ oldIF = getIF();
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ POPF();
+ }
+ else /* USE32 */
+ {
+ POPFD();
+ }
+#ifdef PIG
+ if (getIF()==1 && oldIF==0)
+ {
+ /* locally update IP - interrupts are supressed after POPF */
+ UPDATE_INTEL_IP(p);
+
+ /* We need to pig sync one instr *after* an POPF that enabled
+ * interrupts, because the A4CPU might need to take a H/W interrupt
+ */
+
+ single_instruction_delay = TRUE;
+ PIG_SYNCH(CHECK_ALL);
+
+ goto NEXT_INST;
+ }
+#endif /* PIG */
+
+ quick_mode = FALSE;
+ break;
+ }
+
+ case 0x9e: /* T0 SAHF */
+ SAHF();
+ break;
+
+ case 0x9f: /* T0 LAHF */
+ LAHF();
+ break;
+
+ case 0xa0: /* T4 MOV Fal Ob */
+ D_Ob(1, RO1, PG_R);
+ F_Ob(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Fal(0);
+ break;
+
+ case 0xa1: /* T4 MOV F(e)ax Ov */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ow(1, RO1, PG_R);
+ F_Ow(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Fax(0);
+ }
+ else /* USE32 */
+ {
+ D_Od(1, RO1, PG_R);
+ F_Od(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Feax(0);
+ }
+ break;
+
+ case 0xa2: /* T4 MOV Ob Fal */
+ D_Ob(0, WO0, PG_W);
+ F_Fal(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ob(0);
+ break;
+
+ case 0xa3: /* T4 MOV Ov F(e)ax */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ow(0, WO0, PG_W);
+ F_Fax(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ow(0);
+ }
+ else /* USE32 */
+ {
+ D_Od(0, WO0, PG_W);
+ F_Feax(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Od(0);
+ }
+ break;
+
+ case 0xa4: /* T4 MOVSB Yb Xb */
+ STRING_COUNT;
+
+ while ( rep_count )
+ {
+ D_Xb(1, RO1, PG_R);
+ D_Yb(0, WO0, PG_W);
+ F_Xb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yb(0);
+ C_Xb(1);
+ P_Yb(0);
+ /* KNOWN BUG #1. */
+ }
+ break;
+
+ case 0xa5: /* T4 MOVSW Yv Xv */
+ STRING_COUNT;
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ while ( rep_count )
+ {
+ D_Xw(1, RO1, PG_R);
+ D_Yw(0, WO0, PG_W);
+ F_Xw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yw(0);
+ C_Xw(1);
+ P_Yw(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ while ( rep_count )
+ {
+ D_Xd(1, RO1, PG_R);
+ D_Yd(0, WO0, PG_W);
+ F_Xd(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yd(0);
+ C_Xd(1);
+ P_Yd(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+ break;
+
+ case 0xa6: /* T6 CMPSB Xb Yb */
+ STRING_COUNT;
+
+ while ( rep_count )
+ {
+ D_Xb(0, RO0, PG_R);
+ D_Yb(1, RO1, PG_R);
+ F_Xb(0);
+ F_Yb(1);
+ CMP(ops[0].sng, ops[1].sng, 8);
+ rep_count--;
+ C_Xb(0);
+ C_Yb(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ break;
+
+ case 0xa7: /* T6 CMPSW Xv Yv */
+ STRING_COUNT;
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ while ( rep_count )
+ {
+ D_Xw(0, RO0, PG_R);
+ D_Yw(1, RO1, PG_R);
+ F_Xw(0);
+ F_Yw(1);
+ CMP(ops[0].sng, ops[1].sng, 16);
+ rep_count--;
+ C_Xw(0);
+ C_Yw(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ while ( rep_count )
+ {
+ D_Xd(0, RO0, PG_R);
+ D_Yd(1, RO1, PG_R);
+ F_Xd(0);
+ F_Yd(1);
+ CMP(ops[0].sng, ops[1].sng, 32);
+ rep_count--;
+ C_Xd(0);
+ C_Yd(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ }
+ break;
+
+ case 0xa8: /* T6 TEST Fal Ib */ inst32328 = TEST; goto TYPE3C;
+ case 0xa9: /* T6 TEST F(e)ax Iv */ inst32328 = TEST; goto TYPE3D;
+
+ case 0xaa: /* T4 STOSB Yb Fal */
+ STRING_COUNT;
+
+ F_Fal(1);
+ while ( rep_count )
+ {
+ D_Yb(0, WO0, PG_W);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yb(0);
+ P_Yb(0);
+ /* KNOWN BUG #1. */
+ }
+ break;
+
+ case 0xab: /* T4 STOSW Yv F(e)ax */
+ STRING_COUNT;
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ F_Fax(1);
+ while ( rep_count )
+ {
+ D_Yw(0, WO0, PG_W);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yw(0);
+ P_Yw(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ F_Feax(1);
+ while ( rep_count )
+ {
+ D_Yd(0, WO0, PG_W);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ C_Yd(0);
+ P_Yd(0);
+ /* KNOWN BUG #1. */
+ }
+ }
+ break;
+
+ case 0xac: /* T4 LODSB Fal Xb */
+ STRING_COUNT;
+
+ while ( rep_count )
+ {
+ D_Xb(1, RO1, PG_R);
+ F_Xb(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ P_Fal(0);
+ C_Xb(1);
+ /* KNOWN BUG #1. */
+ }
+ break;
+
+ case 0xad: /* T4 LODSW F(e)ax Xv */
+ STRING_COUNT;
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ while ( rep_count )
+ {
+ D_Xw(1, RO1, PG_R);
+ F_Xw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ P_Fax(0);
+ C_Xw(1);
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ while ( rep_count )
+ {
+ D_Xd(1, RO1, PG_R);
+ F_Xd(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ rep_count--;
+ P_Feax(0);
+ C_Xd(1);
+ /* KNOWN BUG #1. */
+ }
+ }
+ break;
+
+ case 0xae: /* T6 SCASB Fal Yb */
+ STRING_COUNT;
+
+ F_Fal(0);
+ while ( rep_count )
+ {
+ D_Yb(1, RO1, PG_R);
+ F_Yb(1);
+ CMP(ops[0].sng, ops[1].sng, 8);
+ rep_count--;
+ C_Yb(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ break;
+
+ case 0xaf: /* T6 SCASW F(e)ax Yv */
+ STRING_COUNT;
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ F_Fax(0);
+ while ( rep_count )
+ {
+ D_Yw(1, RO1, PG_R);
+ F_Yw(1);
+ CMP(ops[0].sng, ops[1].sng, 16);
+ rep_count--;
+ C_Yw(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ }
+ else /* USE32 */
+ {
+ F_Feax(0);
+ while ( rep_count )
+ {
+ D_Yd(1, RO1, PG_R);
+ F_Yd(1);
+ CMP(ops[0].sng, ops[1].sng, 32);
+ rep_count--;
+ C_Yd(1);
+ if ( rep_count &&
+ ( repeat == REP_E && GET_ZF() == 0 ||
+ repeat == REP_NE && GET_ZF() == 1 )
+ )
+ break;
+ /* KNOWN BUG #1. */
+ }
+ }
+ break;
+
+ case 0xb0: /* T4 MOV Hb Ib */
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ D_Hb(0);
+ D_Ib(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Hb(0);
+ break;
+
+ case 0xb8: /* T4 MOV Hv Iv */
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Hw(0);
+ D_Iw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Hw(0);
+ }
+ else /* USE32 */
+ {
+ D_Hd(0);
+ D_Id(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Hd(0);
+ }
+ break;
+
+ case 0xc0:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Eb Ib */ instp32328 = ROL; goto TYPE80_0;
+ case 1: /* T5 ROR Eb Ib */ instp32328 = ROR; goto TYPE80_0;
+ case 2: /* T5 RCL Eb Ib */ instp32328 = RCL; goto TYPE80_0;
+ case 3: /* T5 RCR Eb Ib */ instp32328 = RCR; goto TYPE80_0;
+ case 4: /* T5 SHL Eb Ib */ instp32328 = SHL; goto TYPE80_0;
+ case 5: /* T5 SHR Eb Ib */ instp32328 = SHR; goto TYPE80_0;
+ case 6: /* T5 SHL Eb Ib */ instp32328 = SHL; goto TYPE80_0;
+ case 7: /* T5 SAR Eb Ib */ instp32328 = SAR; goto TYPE80_0;
+ }
+
+ case 0xc1:
+ modRM = GET_INST_BYTE(p);
+
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Ev Ib */ instp32328 = ROL; break;
+ case 1: /* T5 ROR Ev Ib */ instp32328 = ROR; break;
+ case 2: /* T5 RCL Ev Ib */ instp32328 = RCL; break;
+ case 3: /* T5 RCR Ev Ib */ instp32328 = RCR; break;
+ case 4: /* T5 SHL Ev Ib */ instp32328 = SHL; break;
+ case 5: /* T5 SHR Ev Ib */ instp32328 = SHR; break;
+ case 6: /* T5 SHL Ev Ib */ instp32328 = SHL; break;
+ case 7: /* T5 SAR Ev Ib */ instp32328 = SAR; break;
+ }
+
+TYPEC1:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ D_Ib(1);
+ F_Ew(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ D_Ib(1);
+ F_Ed(0);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xc2: /* T2 RET Iw */
+ inst32 = RETN;
+ took_absolute_toc = TRUE;
+TYPEC2:
+
+ D_Iw(0);
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0xc3: /* T2 RET I0 */
+ inst32 = RETN;
+ took_absolute_toc = TRUE;
+TYPEC3:
+
+ F_I0(0);
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0xc4: /* T4 LES Gv Mp */
+ instp32p32 = LES;
+TYPEC4:
+
+ modRM = GET_INST_BYTE(p);
+ if (((modRM & 0xfc) == 0xc4) && (instp32p32 == LES)) {
+ /*
+ * It's a c4c? BOP.
+ * The bop routine itself will read the argument, but
+ * we read it here so that we get the next EIP correct.
+ */
+ int nField, i;
+
+ D_Ib(0);
+ nField = modRM & 3;
+ immed = 0;
+ for (i = 0; i < nField; i++)
+ {
+ immed |= (ULONG)GET_INST_BYTE(p);
+ immed <<= 8;
+ }
+ immed |= ops[0].sng;
+#ifdef PIG
+ if (immed == 0xfe)
+ SET_EIP(CCPU_save_EIP);
+ else
+ UPDATE_INTEL_IP(p);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_NO_EXEC); /* Everything checkable up to this point */
+#else /* PIG */
+ UPDATE_INTEL_IP(p);
+ if ((immed & 0xff) == 0xfe)
+ {
+ switch(immed)
+ {
+#if defined(SFELLOW)
+ case 0x03fe:
+ SfdelayUSecs();
+ break;
+ case 0x05fe:
+ SfsasTouchBop();
+ break;
+ case 0x06fe:
+ SfscatterGatherSasTouch();
+ break;
+#endif /* SFELLOW */
+ case 0xfe:
+ c_cpu_unsimulate();
+ /* Never returns (?) */
+ default:
+ EDL_fast_bop(immed);
+ break;
+ }
+ }
+ else
+ {
+ in_C = 1;
+ bop(ops[0].sng);
+ in_C = 0;
+ }
+ CANCEL_HOST_IP();
+ SYNCH_TICK();
+#endif /* PIG */
+ break;
+ }
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Gw(0);
+ D_Mp16(1, RO1, PG_R);
+ F_Mp16(1);
+ (*instp32p32)(&ops[0].sng, ops[1].mlt);
+ P_Gw(0);
+ }
+ else /* USE32 */
+ {
+ D_Gd(0);
+ D_Mp32(1, RO1, PG_R);
+ F_Mp32(1);
+ (*instp32p32)(&ops[0].sng, ops[1].mlt);
+ P_Gd(0);
+ }
+ break;
+
+ case 0xc5: /* T4 LDS Gv Mp */
+ instp32p32 = LDS;
+ goto TYPEC4;
+
+ case 0xc6:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T4 MOV Eb Ib */
+ D_Eb(0, WO0, PG_W);
+ D_Ib(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Eb(0);
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ Int6();
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0xc7:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T4 MOV Ev Iv */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, WO0, PG_W);
+ D_Iw(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, WO0, PG_W);
+ D_Id(1);
+ ops[0].sng = ops[1].sng; /*MOV(&ops[0].sng, ops[1].sng);*/
+ P_Ed(0);
+ }
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ Int6();
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0xc8: /* T6 ENTER Iw Ib */
+ D_Iw(0);
+ D_Ib(1);
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ ENTER16(ops[0].sng, ops[1].sng);
+ }
+ else /* USE32 */
+ {
+ ENTER32(ops[0].sng, ops[1].sng);
+ }
+ break;
+
+ case 0xc9: /* T0 LEAVE */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ LEAVE16();
+ }
+ else /* USE32 */
+ {
+ LEAVE32();
+ }
+ break;
+
+ case 0xca: /* T2 RET Iw */
+ inst32 = RETF;
+ took_absolute_toc = TRUE;
+ goto TYPEC2;
+ case 0xcb: /* T2 RET I0 */
+ inst32 = RETF;
+ took_absolute_toc = TRUE;
+ goto TYPEC3;
+
+ case 0xcc: /* T2 INT I3 */
+ took_absolute_toc = TRUE;
+ F_I3(0);
+ UPDATE_INTEL_IP(p);
+ start_trap = 0; /* clear any pending TF exception */
+ INTx(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0xcd: /* T2 INT Ib */
+ if ( GET_VM() == 1 && GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_INT_ACCESS);
+ took_absolute_toc = TRUE;
+ D_Ib(0);
+ UPDATE_INTEL_IP(p);
+ start_trap = 0; /* clear any pending TF exception */
+ INTx(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0xce: /* T0 INTO */
+ if ( GET_OF() )
+ {
+ took_absolute_toc = TRUE;
+ UPDATE_INTEL_IP(p);
+ start_trap = 0; /* clear any pending TF exception */
+ INTO();
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ }
+ break;
+
+ case 0xcf: /* T0 IRET */
+ if ( GET_VM() == 1 && GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_IRET_ACCESS);
+ took_absolute_toc = TRUE;
+ UPDATE_INTEL_IP(p);
+ IRET();
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ /* Dont do interrupt checks etc after an IRET */
+#ifdef PIG
+ /* If the destination is going to page fault, or need
+ * accessing, then the EDL CPU will do so before issuing
+ * the pig synch. We use the dasm386 decode to prefetch
+ * a single instruction which mimics the EDL Cpu's behaviour
+ * when close to a page boundary.
+ */
+ prefetch_1_instruction(); /* Will PF if destination not present */
+ ccpu_synch_count++;
+ c_cpu_unsimulate();
+#endif /* PIG */
+
+ goto NEXT_INST;
+ break;
+
+ case 0xd0:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Eb I1 */ instp32328 = ROL; break;
+ case 1: /* T5 ROR Eb I1 */ instp32328 = ROR; break;
+ case 2: /* T5 RCL Eb I1 */ instp32328 = RCL; break;
+ case 3: /* T5 RCR Eb I1 */ instp32328 = RCR; break;
+ case 4: /* T5 SHL Eb I1 */ instp32328 = SHL; break;
+ case 5: /* T5 SHR Eb I1 */ instp32328 = SHR; break;
+ case 6: /* T5 SHL Eb I1 */ instp32328 = SHL; break;
+ case 7: /* T5 SAR Eb I1 */ instp32328 = SAR; break;
+ }
+ D_Eb(0, RW0, PG_W);
+ F_Eb(0);
+ F_I1(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Eb(0);
+ break;
+
+ case 0xd1:
+ modRM = GET_INST_BYTE(p);
+
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Ev I1 */ instp32328 = ROL; break;
+ case 1: /* T5 ROR Ev I1 */ instp32328 = ROR; break;
+ case 2: /* T5 RCL Ev I1 */ instp32328 = RCL; break;
+ case 3: /* T5 RCR Ev I1 */ instp32328 = RCR; break;
+ case 4: /* T5 SHL Ev I1 */ instp32328 = SHL; break;
+ case 5: /* T5 SHR Ev I1 */ instp32328 = SHR; break;
+ case 6: /* T5 SHL Ev I1 */ instp32328 = SHL; break;
+ case 7: /* T5 SAR Ev I1 */ instp32328 = SAR; break;
+ }
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ F_Ew(0);
+ F_I1(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ F_Ed(0);
+ F_I1(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xd2:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Eb Fcl */ instp32328 = ROL; break;
+ case 1: /* T5 ROR Eb Fcl */ instp32328 = ROR; break;
+ case 2: /* T5 RCL Eb Fcl */ instp32328 = RCL; break;
+ case 3: /* T5 RCR Eb Fcl */ instp32328 = RCR; break;
+ case 4: /* T5 SHL Eb Fcl */ instp32328 = SHL; break;
+ case 5: /* T5 SHR Eb Fcl */ instp32328 = SHR; break;
+ case 6: /* T5 SHL Eb Fcl */ instp32328 = SHL; break;
+ case 7: /* T5 SAR Eb Fcl */ instp32328 = SAR; break;
+ }
+ D_Eb(0, RW0, PG_W);
+ F_Eb(0);
+ F_Fcl(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 8);
+ P_Eb(0);
+ break;
+
+ case 0xd3:
+ modRM = GET_INST_BYTE(p);
+
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T5 ROL Ev Fcl */ instp32328 = ROL; break;
+ case 1: /* T5 ROR Ev Fcl */ instp32328 = ROR; break;
+ case 2: /* T5 RCL Ev Fcl */ instp32328 = RCL; break;
+ case 3: /* T5 RCR Ev Fcl */ instp32328 = RCR; break;
+ case 4: /* T5 SHL Ev Fcl */ instp32328 = SHL; break;
+ case 5: /* T5 SHR Ev Fcl */ instp32328 = SHR; break;
+ case 6: /* T5 SHL Ev Fcl */ instp32328 = SHL; break;
+ case 7: /* T5 SAR Ev Fcl */ instp32328 = SAR; break;
+ }
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ F_Ew(0);
+ F_Fcl(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ F_Ed(0);
+ F_Fcl(1);
+ (*instp32328)(&ops[0].sng, ops[1].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 0xd4: /* T2 AAM Ib */
+ inst32 = AAM;
+TYPED4:
+
+ D_Ib(0);
+ (*inst32)(ops[0].sng);
+ break;
+
+ case 0xd5: /* T2 AAD Ib */ inst32 = AAD; goto TYPED4;
+
+ case 0xd6: /* T2 BOP Ib */
+ D_Ib(0);
+ UPDATE_INTEL_IP(p);
+
+ PIG_SYNCH(CHECK_NO_EXEC);
+
+#ifndef PIG
+ if (ops[0].sng == 0xfe)
+ {
+ c_cpu_unsimulate();
+ }
+ in_C = 1;
+ bop(ops[0].sng);
+ in_C = 0;
+ CANCEL_HOST_IP();
+#endif /* PIG */
+ SYNCH_TICK();
+ break;
+
+ case 0xd7: /* T2 XLAT Z */
+ D_Z(0, RO0, PG_R);
+ F_Z(0);
+ XLAT(ops[0].sng);
+ break;
+
+ case 0xd8: /* T2 NPX ??? */
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ if ( GET_EM() || GET_TS() )
+ Int7();
+
+ if (NpxIntrNeeded)
+ {
+ TakeNpxExceptionInt(); /* should set up ISR */
+ goto DO_INST; /* run ISR */
+ }
+
+#ifdef PIG
+ /* Must get npx registers from test CPU
+ * This is lazily done for efficiency.
+ */
+ c_checkCpuNpxRegisters();
+#endif /* PIG */
+
+ modRM = GET_INST_BYTE(p);
+ ZFRSRVD(((opcode-0xd8)*0x100) + modRM);
+ break;
+
+ case 0xe0: /* T2 LOOPNE Jb */
+ inst32 = LOOPNE16;
+ inst232 = LOOPNE32;
+TYPEE0:
+
+ D_Jb(0);
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ if ( GET_ADDRESS_SIZE() == USE16 )
+ {
+ (*inst32)(ops[0].sng);
+ }
+ else /* USE32 */
+ {
+ (*inst232)(ops[0].sng);
+ }
+ CANCEL_HOST_IP();
+
+#ifdef PIG
+ if (single_instruction_delay && !took_relative_jump)
+ {
+ if (single_instruction_delay_enable)
+ {
+ save_last_xcptn_details("STI/POPF blindspot\n", 0, 0, 0, 0, 0);
+ PIG_SYNCH(CHECK_NO_EXEC);
+ }
+ else
+ {
+ save_last_xcptn_details("STI/POPF problem\n", 0, 0, 0, 0, 0);
+ }
+ break;
+ }
+#ifdef SYNCH_BOTH_WAYS
+ took_relative_jump = TRUE;
+#endif /* SYNCH_BOTH_WAYS */
+ if (took_relative_jump)
+ {
+ PIG_SYNCH(CHECK_ALL);
+ }
+#endif /* PIG */
+ break;
+
+ case 0xe1: /* T2 LOOPE Jb */
+ inst32 = LOOPE16;
+ inst232 = LOOPE32;
+ goto TYPEE0;
+
+ case 0xe2: /* T2 LOOP Jb */
+ inst32 = LOOP16;
+ inst232 = LOOP32;
+ goto TYPEE0;
+
+ case 0xe3: /* T2 JCXZ Jb */
+ inst32 = JCXZ;
+ inst232 = JECXZ;
+ goto TYPEE0;
+
+ case 0xe4: /* T4 INB Fal Ib */
+ D_Ib(1);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, BYTE_WIDTH);
+
+ IN8(&ops[0].sng, ops[1].sng);
+ P_Fal(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_AL);
+ quick_mode = FALSE;
+ break;
+
+ case 0xe5: /* T4 INW F(e)ax Ib */
+ D_Ib(1);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, WORD_WIDTH);
+
+ IN16(&ops[0].sng, ops[1].sng);
+ P_Fax(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_AX);
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, DWORD_WIDTH);
+
+ IN32(&ops[0].sng, ops[1].sng);
+ P_Feax(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_EAX);
+ }
+ quick_mode = FALSE;
+ break;
+
+ case 0xe6: /* T6 OUTB Ib Fal */
+ D_Ib(0);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, BYTE_WIDTH);
+
+ F_Fal(1);
+ OUT8(ops[0].sng, ops[1].sng);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+ if (ops[0].sng == 0x60)
+ {
+ /* This may be a change of A20 wrap status */
+ PIG_SYNCH(CHECK_NO_A20);
+ }
+ else
+ {
+ PIG_SYNCH(CHECK_ALL);
+ }
+#else
+ SYNCH_TICK();
+#endif
+ break;
+
+ case 0xe7: /* T6 OUTW Ib F(e)ax */
+ D_Ib(0);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, WORD_WIDTH);
+
+ F_Fax(1);
+ OUT16(ops[0].sng, ops[1].sng);
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, DWORD_WIDTH);
+
+ F_Feax(1);
+ OUT32(ops[0].sng, ops[1].sng);
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_ALL);
+ quick_mode = FALSE;
+ break;
+
+ case 0xe8: /* T2 CALL Jv */
+ inst32 = CALLR;
+ took_absolute_toc = TRUE;
+TYPEE8:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Jw(0);
+ }
+ else /* USE32 */
+ {
+ D_Jd(0);
+ }
+
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 0xe9: /* T2 JMP Jv */
+ inst32 = JMPR;
+ took_absolute_toc = TRUE;
+ goto TYPEE8;
+ case 0xea: /* T2 JMP Ap */
+ instp32 = JMPF;
+ took_absolute_toc = TRUE;
+ goto TYPE9A;
+ case 0xeb: /* T2 JMP Jb */
+ inst32 = JMPR;
+ took_absolute_toc = TRUE;
+ goto TYPE70;
+
+ case 0xec: /* T4 INB Fal Fdx */
+ F_Fdx(1);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, BYTE_WIDTH);
+
+ IN8(&ops[0].sng, ops[1].sng);
+ P_Fal(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_AL);
+ quick_mode = FALSE;
+ break;
+
+ case 0xed: /* T4 INW F(e)ax Fdx */
+ F_Fdx(1);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, WORD_WIDTH);
+
+ IN16(&ops[0].sng, ops[1].sng);
+ P_Fax(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_AX);
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[1].sng, DWORD_WIDTH);
+
+ IN32(&ops[0].sng, ops[1].sng);
+ P_Feax(0);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_NO_EAX);
+ }
+ quick_mode = FALSE;
+ break;
+
+ case 0xee: /* T6 OUTB Fdx Fal */
+ F_Fdx(0);
+
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, BYTE_WIDTH);
+
+ F_Fal(1);
+ OUT8(ops[0].sng, ops[1].sng);
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_ALL);
+ quick_mode = FALSE;
+ break;
+
+ case 0xef: /* T6 OUTW Fdx F(e)ax */
+ F_Fdx(0);
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, WORD_WIDTH);
+
+ F_Fax(1);
+ OUT16(ops[0].sng, ops[1].sng);
+ }
+ else /* USE32 */
+ {
+ if ( GET_CPL() > GET_IOPL() || GET_VM() )
+ check_io_permission_map(ops[0].sng, DWORD_WIDTH);
+
+ F_Feax(1);
+ OUT32(ops[0].sng, ops[1].sng);
+ }
+#ifdef PIG
+ UPDATE_INTEL_IP(p);
+#endif
+ PIG_SYNCH(CHECK_ALL);
+ quick_mode = FALSE;
+ break;
+
+ case 0xf0: /* T0 LOCK */
+ CHECK_PREFIX_LENGTH();
+ goto DECODE; /* NB. Incorrect Emulation! */
+
+ case 0xf1:
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0xf2:
+ repeat = REP_NE;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0xf3:
+ repeat = REP_E;
+ CHECK_PREFIX_LENGTH();
+ goto DECODE;
+
+ case 0xf4: /* T0 HLT */
+ if ( GET_CPL() != 0 )
+ GP((IU16)0, FAULT_CCPU_HLT_ACCESS);
+
+ /* Wait for an interrupt */
+
+ UPDATE_INTEL_IP(p);
+ PIG_SYNCH(CHECK_ALL);
+
+#ifndef PIG
+
+ while ( TRUE )
+ {
+ /* RESET ends the halt state. */
+ if ( cpu_interrupt_map & CPU_RESET_EXCEPTION_MASK )
+ break;
+
+ /* An enabled INTR ends the halt state. */
+ if ( GET_IF() && cpu_interrupt_map & CPU_HW_INT_MASK )
+ break;
+
+ /* As time goes by. */
+ if (cpu_interrupt_map & CPU_SIGALRM_EXCEPTION_MASK)
+ {
+ cpu_interrupt_map &= ~CPU_SIGALRM_EXCEPTION_MASK;
+ host_timer_event();
+ }
+
+#ifndef PROD
+ if (cpu_interrupt_map & CPU_SAD_EXCEPTION_MASK)
+ {
+ cpu_interrupt_map &= ~CPU_SAD_EXCEPTION_MASK;
+ force_yoda();
+ }
+#endif /* PROD */
+
+ SYNCH_TICK();
+ QUICK_EVENT_TICK();
+ }
+ quick_mode = FALSE;
+
+#endif /* PIG */
+
+ break;
+
+ case 0xf5: /* T0 CMC */
+ CMC();
+ break;
+
+ case 0xf6:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T6 TEST Eb Ib */
+ case 1:
+ inst32328 = TEST;
+ goto TYPE80_7;
+
+ case 2: /* T1 NOT Eb */
+ D_Eb(0, RW0, PG_W);
+ F_Eb(0);
+ NOT(&ops[0].sng);
+ P_Eb(0);
+ break;
+
+ case 3: /* T1 NEG Eb */
+ instp328 = NEG;
+TYPEF6_3:
+
+ D_Eb(0, RW0, PG_W);
+ F_Eb(0);
+ (*instp328)(&ops[0].sng, 8);
+ P_Eb(0);
+ break;
+
+ case 4: /* T5 MUL Fal Eb */
+ instp3232 = MUL8;
+TYPEF6_4:
+
+ D_Eb(1, RO1, PG_R);
+ F_Fal(0);
+ F_Eb(1);
+ (*instp3232)(&ops[0].sng, ops[1].sng);;
+ P_Fal(0);
+ break;
+
+ case 5: /* T5 IMUL Fal Eb */ instp3232 = IMUL8; goto TYPEF6_4;
+
+ case 6: /* T2 DIV Eb */
+ inst32 = DIV8;
+TYPEF6_6:
+
+ D_Eb(0, RO0, PG_R);
+ F_Eb(0);
+ (*inst32)(ops[0].sng);
+ break;
+
+ case 7: /* T2 IDIV Eb */ inst32 = IDIV8; goto TYPEF6_6;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0xf7:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T6 TEST Ev Iv */
+ case 1:
+ inst32328 = TEST;
+ goto TYPE81_7;
+
+ case 2: /* T1 NOT Ew */
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ F_Ew(0);
+ NOT(&ops[0].sng);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ F_Ed(0);
+ NOT(&ops[0].sng);
+ P_Ed(0);
+ }
+ break;
+
+ case 3: /* T1 NEG Ew */
+ instp328 = NEG;
+TYPEF7_3:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RW0, PG_W);
+ F_Ew(0);
+ (*instp328)(&ops[0].sng, 16);
+ P_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RW0, PG_W);
+ F_Ed(0);
+ (*instp328)(&ops[0].sng, 32);
+ P_Ed(0);
+ }
+ break;
+
+ case 4: /* T5 MUL F(e)ax Ev */
+ instp3232 = MUL16;
+ inst2p3232 = MUL32;
+TYPEF7_4:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(1, RO1, PG_R);
+ F_Fax(0);
+ F_Ew(1);
+ (*instp3232)(&ops[0].sng, ops[1].sng);;
+ P_Fax(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(1, RO1, PG_R);
+ F_Feax(0);
+ F_Ed(1);
+ (*inst2p3232)(&ops[0].sng, ops[1].sng);
+ P_Feax(0);
+ }
+ break;
+
+ case 5: /* T5 IMUL F(e)ax Ev */
+ instp3232 = IMUL16;
+ inst2p3232 = IMUL32;
+ goto TYPEF7_4;
+
+ case 6: /* T2 DIV Ev */
+ inst32 = DIV16;
+ inst232 = DIV32;
+TYPEF7_6:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ F_Ew(0);
+ (*inst32)(ops[0].sng);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RO0, PG_R);
+ F_Ed(0);
+ (*inst232)(ops[0].sng);
+ }
+ break;
+
+ case 7: /* T5 IDIV Ev */
+ inst32 = IDIV16;
+ inst232 = IDIV32;
+ goto TYPEF7_6;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+
+ case 0xf8: /* T0 CLC */
+ CLC();
+ break;
+
+ case 0xf9: /* T0 STC */
+ STC();
+ break;
+
+ case 0xfa: /* T0 CLI */
+ if ( GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_CLI_ACCESS);
+ CLI();
+ break;
+
+ case 0xfb: /* T0 STI */
+ if ( GET_CPL() > GET_IOPL() )
+ GP((IU16)0, FAULT_CCPU_STI_ACCESS);
+ STI();
+
+ /* locally update IP - interrupts are supressed after STI */
+ UPDATE_INTEL_IP(p);
+
+#ifdef PIG
+ /* We need to pig sync one instr *after* an STI that enabled
+ * interrupts, because the A4CPU might need to take a H/W interrupt
+ */
+ single_instruction_delay = TRUE;
+ PIG_SYNCH(CHECK_ALL);
+#endif /* PIG */
+ goto NEXT_INST;
+
+ case 0xfc: /* T0 CLD */
+ CLD();
+ break;
+
+ case 0xfd: /* T0 STD */
+ STD();
+ break;
+
+ case 0xfe:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T1 INC Eb */ instp328 = INC; goto TYPEF6_3;
+ case 1: /* T1 DEC Eb */ instp328 = DEC; goto TYPEF6_3;
+
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ Int6();
+ break;
+ }
+ break;
+
+ case 0xff:
+ modRM = GET_INST_BYTE(p);
+ switch ( GET_XXX(modRM) )
+ {
+ case 0: /* T1 INC Ev */ instp328 = INC; goto TYPEF7_3;
+ case 1: /* T1 DEC Ev */ instp328 = DEC; goto TYPEF7_3;
+
+ case 2: /* T2 CALL Ev */
+ inst32 = CALLN;
+ took_absolute_toc = TRUE;
+TYPEFF_2:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Ew(0, RO0, PG_R);
+ F_Ew(0);
+ }
+ else /* USE32 */
+ {
+ D_Ed(0, RO0, PG_R);
+ F_Ed(0);
+ }
+
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*inst32)(ops[0].sng);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 3: /* T2 CALL Mp */
+ instp32 = CALLF;
+ took_absolute_toc = TRUE;
+TYPEFF_3:
+
+ if ( GET_OPERAND_SIZE() == USE16 )
+ {
+ D_Mp16(0, RO0, PG_R);
+ F_Mp16(0);
+ }
+ else /* USE32 */
+ {
+ D_Mp32(0, RO0, PG_R);
+ F_Mp32(0);
+ }
+
+ UPDATE_INTEL_IP_USE_OP_SIZE(p);
+ (*instp32)(ops[0].mlt);
+ CANCEL_HOST_IP();
+ PIG_SYNCH(CHECK_ALL);
+ break;
+
+ case 4: /* T2 JMP Ev */
+ inst32 = JMPN;
+ took_absolute_toc = TRUE;
+ goto TYPEFF_2;
+ case 5: /* T2 JMP Mp */
+ instp32 = JMPF;
+ took_absolute_toc = TRUE;
+ goto TYPEFF_3;
+ case 6: /* T2 PUSH Ev */
+ inst32 = PUSH;
+ inst232 = PUSH;
+ goto TYPEF7_6;
+
+ case 7:
+ Int6();
+ break;
+ } /* end switch ( GET_XXX(modRM) ) */
+ break;
+ } /* end switch ( opcode ) */
+
+ /* >>>>> Instruction Completed. <<<<< */
+
+ /* Reset default mode */
+ SET_OPERAND_SIZE(GET_CS_AR_X());
+ SET_ADDRESS_SIZE(GET_CS_AR_X());
+
+ /*
+ Increment instruction pointer.
+ NB. For most instructions we increment the IP after processing
+ the instruction, however all users of the IP (eg flow of control)
+ instructions are coded on the basis that IP has already been
+ updated, so where necessary we update IP before the instruction.
+ In those cases p_start is also updated so that this code can
+ tell that IP has already been updated.
+ */
+ if ( p != p_start )
+ UPDATE_INTEL_IP(p);
+
+ /*
+ Move start of inst to the next inst. We have successfully
+ completed instruction and are now going on to inter-instruction
+ checks.
+ */
+ CCPU_save_EIP = GET_EIP();
+
+ /*
+ Now check for interrupts/external events/breakpoints...
+ */
+
+ if ( quick_mode && GET_DR(DR_DSR) == 0 )
+ goto DO_INST;
+
+#ifdef SYNCH_TIMERS
+ CHECK_INTERRUPT:
+#endif /* SYNCH_TIMERS */
+ quick_mode = FALSE;
+
+ /* Action RESET first. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+#ifdef SYNCH_TIMERS
+ if (took_absolute_toc || took_relative_jump)
+#endif /* SYNCH_TIMERS */
+ if (cpu_interrupt_map & CPU_RESET_EXCEPTION_MASK)
+ {
+ cpu_interrupt_map &= ~CPU_RESET_EXCEPTION_MASK;
+ c_cpu_reset();
+ doing_contributory = FALSE;
+ doing_page_fault = FALSE;
+ doing_double_fault = FALSE;
+ doing_fault = FALSE;
+ EXT = INTERNAL;
+ SET_POP_DISP(0);
+ goto NEXT_INST;
+ }
+
+ /* Action Insignia (ie non Intel) Processing. <<<<<<<<<<<<<<< */
+
+#ifdef SYNCH_TIMERS
+ if (took_absolute_toc || took_relative_jump)
+#endif /* SYNCH_TIMERS */
+ if (cpu_interrupt_map & CPU_SIGALRM_EXCEPTION_MASK)
+ {
+ cpu_interrupt_map &= ~CPU_SIGALRM_EXCEPTION_MASK;
+ host_timer_event();
+ }
+
+ if (cpu_interrupt_map & CPU_SAD_EXCEPTION_MASK)
+ {
+ cpu_interrupt_map &= ~CPU_SAD_EXCEPTION_MASK;
+ force_yoda();
+ }
+
+ /* INTEL inter instruction processing. <<<<<<<<<<<<<<<<<<<<<<<*/
+
+ /* Reset default mode */
+ SET_OPERAND_SIZE(GET_CS_AR_X());
+ SET_ADDRESS_SIZE(GET_CS_AR_X());
+
+ /* Check for single step trap */
+ if ( start_trap )
+ {
+ SET_DR(DR_DSR, GET_DR(DR_DSR) | DSR_BS_MASK); /* set BS */
+ Int1_t(); /* take TF trap */
+ }
+
+ /* check for debug traps */
+ if ( GET_DR(DR_DSR) &
+ (DSR_BT_MASK | DSR_B3_MASK | DSR_B2_MASK | DSR_B1_MASK |
+ DSR_B0_MASK) )
+ {
+ Int1_t(); /* at least one breakpoint set from:-
+ T-bit or DATA Breakpoints */
+ }
+
+ if ( nr_inst_break && GET_RF() == 0 )
+ {
+ check_for_inst_exception(GET_CS_BASE() + GET_EIP());
+ if ( GET_DR(DR_DSR) )
+ {
+ Int1_f(); /* a CODE Breakpoint triggered */
+ }
+ }
+
+#ifdef SYNCH_TIMERS
+ if (took_absolute_toc || took_relative_jump)
+#endif /* SYNCH_TIMERS */
+#ifndef SFELLOW
+ if (GET_IF() && (cpu_interrupt_map & CPU_HW_INT_MASK))
+ {
+
+/*
+ * IRET hooks aren't yet used by the C CPU, but we might want to do in
+ * future.
+ */
+
+ IU32 hook_address;
+
+ cpu_hw_interrupt_number = ica_intack(&hook_address);
+ cpu_interrupt_map &= ~CPU_HW_INT_MASK;
+ EXT = EXTERNAL;
+ SYNCH_TICK();
+ do_intrupt(cpu_hw_interrupt_number, FALSE, FALSE, (IU16)0);
+ CCPU_save_EIP = GET_EIP(); /* to reflect IP change */
+ }
+#else /* SFELLOW */
+ if (GET_IF() && (cpu_interrupt_map & (CPU_HW_INT_MASK | CPU_HW_NPX_INT_MASK)))
+ {
+ /* service any pending real H/W interrupt first */
+ if (cpu_interrupt_map & CPU_HW_INT_MASK)
+ {
+ cpu_hw_interrupt_number = ica_intack();
+ cpu_interrupt_map &= ~CPU_HW_INT_MASK;
+ EXT = EXTERNAL;
+ do_intrupt(cpu_hw_interrupt_number, FALSE, FALSE, (IU16)0);
+ CCPU_save_EIP = GET_EIP(); /* to reflect IP change */
+ }
+ else
+ if (cpu_interrupt_map & CPU_HW_NPX_INT_MASK)
+ {
+ cpu_hw_interrupt_number = IRQ5_SLAVE_PIC + VectorBase8259Slave();
+ cpu_interrupt_map &= ~CPU_HW_NPX_INT_MASK;
+ EXT = EXTERNAL;
+ do_intrupt(cpu_hw_interrupt_number, FALSE, FALSE, (IU16)0);
+ CCPU_save_EIP = GET_EIP(); /* to reflect IP change */
+ }
+ }
+#endif /* SFELLOW */
+
+#ifdef PIG
+ if ( pig_synch_required )
+ {
+ if (IgnoringThisSynchPoint(GET_CS_SELECTOR(), GET_EIP()))
+ {
+ pig_synch_required = FALSE;
+ }
+ else
+ {
+ /* If the destination is going to page fault, or need
+ * accessing, then the EDL CPU will do so before issuing
+ * the pig synch. We use the dasm386 decode to prefetch
+ * a single instruction which mimics the EDL Cpu's behaviour
+ * when close to a page boundary.
+ */
+ prefetch_1_instruction(); /* Will PF if destination not present */
+#if defined(SFELLOW)
+ /*
+ * Check for occurrence of memory-mapped input.
+ * This initial crude implementation just leaves the entire synch
+ * section unchecked.
+ */
+ if ( pig_mmio_info.flags & MM_INPUT_OCCURRED )
+ {
+ pig_cpu_action = CHECK_NONE; /* cos' its effects are unknown */
+#if COLLECT_MMIO_STATS
+ if ( ++pig_mmio_info.mm_input_section_count == 0 )
+ pig_mmio_info.flags |= MM_INPUT_SECTION_COUNT_WRAPPED;
+#endif /* COLLECT_MMIO_STATS */
+ }
+ if ( pig_mmio_info.flags & MM_OUTPUT_OCCURRED )
+ {
+#if COLLECT_MMIO_STATS
+ if ( ++pig_mmio_info.mm_output_section_count == 0 )
+ pig_mmio_info.flags |= MM_OUTPUT_SECTION_COUNT_WRAPPED;
+#endif /* COLLECT_MMIO_STATS */
+ }
+#endif /* SFELLOW */
+ ccpu_synch_count++;
+ c_cpu_unsimulate();
+ }
+ }
+#endif /* PIG */
+
+NEXT_INST:
+
+ CCPU_save_EIP = GET_EIP(); /* to reflect IP change */
+
+#if defined(SFELLOW) && !defined(PROD)
+ if (sf_debug_char_waiting())
+ {
+ force_yoda();
+ }
+#endif /* SFELLOW && !PROD */
+
+ /* Reset default mode */
+ SET_OPERAND_SIZE(GET_CS_AR_X());
+ SET_ADDRESS_SIZE(GET_CS_AR_X());
+ took_relative_jump = FALSE;
+ took_absolute_toc = FALSE;
+
+ SETUP_HOST_IP(p);
+
+ /*
+ THIS IS A CHEAT.
+ The Intel documentation says RF is cleared AFTER all instructions
+ except (POPF, IRET or TASK SWITCH). To save clearing RF for each
+ and every instruction with a special test for the named exceptions
+ we clear RF before the instruction, we are assuming the
+ instruction will now be successful. As all the fault handlers set
+ RF in the pushed flags it will appear that RF was left set when
+ instructions don't run to completion from this point.
+ So although we cheat we intend to have the same effect as the
+ real thing.
+ */
+ SET_RF(0);
+
+ start_trap = GET_TF();
+
+ /* Determine if we can go into quick mode */
+ if ( cpu_interrupt_map == 0 &&
+ start_trap == 0 &&
+ nr_inst_break == 0
+#ifdef PIG
+ && !pig_synch_required
+#endif
+ )
+ {
+ quick_mode = TRUE;
+ }
+
+ goto DO_INST;
+ }
+
+#define MAP_BASE_ADDR 0x66
+
+LOCAL IUM32 width_mask[4] = { 0x1, 0x3, 0, 0xf };
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+/* Check IO access against Permission Map in TSS. */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+LOCAL VOID
+ check_io_permission_map IFN2
+ (
+ IU32, port, /* address of 1st port being accessed */
+ IUM8, width /* bytes (1|2|4) accessed */
+ )
+ {
+ IU16 map_start_offset;
+ IU16 map_word_offset;
+ IU16 map_word;
+
+ /* if invalid or 286 TSS, just take exception */
+ if ( GET_TR_SELECTOR() == 0 || GET_TR_AR_SUPER() == BUSY_TSS )
+ GP((IU16)0, FAULT_CHKIOMAP_BAD_TSS);
+
+ if ( MAP_BASE_ADDR >= GET_TR_LIMIT() )
+ GP((IU16)0, FAULT_CHKIOMAP_BAD_MAP); /* No I/O Map Base Address. */
+
+ /* Read bit map start address */
+ map_start_offset = spr_read_word(GET_TR_BASE() + MAP_BASE_ADDR);
+
+ /* Now try to read reqd word from bit map */
+ map_word_offset = map_start_offset + port/8;
+ if ( map_word_offset >= GET_TR_LIMIT() )
+ GP((IU16)0, FAULT_CHKIOMAP_BAD_TR); /* Map truncated before current port */
+
+ /* Actually read word and check appropriate bits */
+ map_word = spr_read_word(GET_TR_BASE() + map_word_offset);
+ map_word = map_word >> port%8; /* bits to lsb's */
+ if ( map_word & width_mask[width-1] )
+ GP((IU16)0, FAULT_CHKIOMAP_ACCESS); /* Access dis-allowed */
+
+ /* ACCESS OK */
+ }
+
+ /*
+ =====================================================================
+ EXTERNAL FUNCTIONS START HERE.
+ =====================================================================
+ */
+
+#ifndef SFELLOW
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Set the CPU heartbeat timer (for quick events). */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID c_cpu_q_ev_set_count IFN1( IU32, countval )
+ {
+/* printf("setting q counter to %d\n", countval); */
+ cpu_heartbeat = countval;
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Calculate (ie guess) the number of CPU heartbeat timer ticks to */
+ /* will have gone by for a given number of microseconds. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL IU32 c_cpu_calc_q_ev_inst_for_time IFN1( IU32, time )
+ {
+ return ( time );
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Get the CPU heartbeat timer (for quick events). */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL IU32 c_cpu_q_ev_get_count()
+ {
+/* printf("returning q counter as %d\n", cpu_heartbeat); */
+ return cpu_heartbeat;
+ }
+
+#endif /* SFELLOW */
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Set up new page for fast Instruction Decoding. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL IU8
+ ccpu_new_code_page
+
+ IFN1(
+ IU8 **, q /* pntr. to host format IP pointer */
+ )
+
+ /* ANSI */
+ {
+ IU32 ip_phy_addr; /* Used when setting up IP (cf SETUP_HOST_IP) */
+
+ /* update Intel IP up to end of the old page */
+ SET_EIP(GET_EIP() + DIFF_INST_BYTE(*q, p_start));
+
+ /* move onto new page in host format */
+ SETUP_HOST_IP(*q)
+ p_start = *q;
+
+#ifdef PIG
+ return *IncCpuPtrLS8(*q);
+#else /* PIG */
+#ifdef BACK_M
+ return *(*q)--;
+#else
+ return *(*q)++;
+#endif /* BACK_M */
+#endif /* PIG */
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Initialise the CPU. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_init IFN0()
+ {
+ SAVED IBOOL first = TRUE;
+
+#ifdef PIG
+ SAVED char default_flags[] = "faults accessed";
+
+ if (first)
+ {
+ char *s = getenv("FLAGS_IGNORE_DEFAULT");
+ if (s)
+ set_flags_ignore(s);
+ else
+ set_flags_ignore(default_flags);
+ single_instruction_delay_enable = FALSE;
+ s = getenv("SINGLE_INSTRUCTION_BLIND_SPOT");
+ if (s)
+ {
+ if (strcmp(s, "TRUE") == 0)
+ single_instruction_delay_enable = TRUE;
+ else if (strcmp(s, "FALSE") == 0)
+ single_instruction_delay_enable = FALSE;
+ else
+ printf("*** Ignoring getenv(\"SINGLE_INSTRUCTION_BLIND_SPOT\") value\n");
+ printf("STI/POPF %s cause a blind spot after next conditional\n",
+ single_instruction_delay_enable ? "will": "will not");
+ }
+ first = FALSE;
+ }
+#endif /* PIG */
+
+#ifdef NTVDM
+ ccpu386InitThreadStuff();
+#endif
+
+ c_cpu_reset();
+ SET_POP_DISP(0);
+ doing_contributory = FALSE;
+ doing_page_fault = FALSE;
+ doing_double_fault = FALSE;
+ doing_fault = FALSE;
+ EXT = INTERNAL;
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Make CPU aware that external event is pending.
+ * Be careful about modifying this function, as much of the base and host
+ * in A2CPU will modify cpu_interrupt_map directly, rather than going through
+ * this function.
+ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+ GLOBAL VOID
+ c_cpu_interrupt IFN2(CPU_INT_TYPE, type, IU16, number)
+ {
+ switch ( type )
+ {
+ case CPU_HW_RESET:
+ cpu_interrupt_map |= CPU_RESET_EXCEPTION_MASK;
+ break;
+ case CPU_TIMER_TICK:
+ cpu_interrupt_map |= CPU_SIGALRM_EXCEPTION_MASK;
+ break;
+ case CPU_SIGIO_EVENT:
+ cpu_interrupt_map |= CPU_SIGIO_EXCEPTION_MASK;
+ break;
+ case CPU_HW_INT:
+ cpu_interrupt_map |= CPU_HW_INT_MASK;
+ break;
+ case CPU_SAD_INT:
+ cpu_interrupt_map |= CPU_SAD_EXCEPTION_MASK;
+ break;
+ }
+ quick_mode = FALSE;
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Act like CPU 'reset' line activated. (Well nearly) */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_reset IFN0()
+ {
+ IBOOL disableNpx = FALSE;
+
+ /* All FLAGS are cleared */
+ /* NB. VM MUST BE CLEARED BEFORE SEGMENT REGISTERS ARE LOADED. */
+#ifdef SPC486
+ SET_AC(0);
+#endif /* SPC486 */
+ SET_RF(0); SET_VM(0); SET_NT(0); SET_IOPL(0);
+ SET_PF(0); SET_CF(0); SET_AF(0); SET_ZF(0); SET_SF(0); SET_OF(0);
+ SET_TF(0); SET_IF(0); SET_DF(0);
+
+ SET_EIP(0xFFF0);
+ SET_CPL(0);
+
+ SET_CS_SELECTOR(0xF000);
+ SET_CS_BASE(0xf0000); /* Really 0xffff0000 */
+ load_pseudo_descr(CS_REG);
+
+ SET_SS_SELECTOR(0);
+ SET_SS_BASE(0);
+ load_pseudo_descr(SS_REG);
+
+ SET_DS_SELECTOR(0);
+ SET_DS_BASE(0);
+ load_pseudo_descr(DS_REG);
+
+ SET_ES_SELECTOR(0);
+ SET_ES_BASE(0);
+ load_pseudo_descr(ES_REG);
+
+ SET_FS_SELECTOR(0);
+ SET_FS_BASE(0);
+ load_pseudo_descr(FS_REG);
+
+ SET_GS_SELECTOR(0);
+ SET_GS_BASE(0);
+ load_pseudo_descr(GS_REG);
+
+ SET_CR(CR_STAT, 0);
+#ifdef SPC486
+ SET_CD(1);
+ SET_NW(1);
+#endif /* SPC486 */
+
+ SET_DR(DR_DAR0, 0); /* Really Undefined */
+ SET_DR(DR_DAR1, 0); /* Really Undefined */
+ SET_DR(DR_DAR2, 0); /* Really Undefined */
+ SET_DR(DR_DAR3, 0); /* Really Undefined */
+ SET_DR(DR_DSR, 0); /* Really Undefined */
+ MOV_DR((IU32) DR_DCR, (IU32) 0); /* Disable Breakpoints */
+
+ SET_TR(TR_TCR, 0); /* Really Undefined */
+ SET_TR(TR_TDR, 0); /* Really Undefined */
+
+ SET_IDT_BASE(0); SET_IDT_LIMIT(0x3ff);
+
+ /* Really Undefined */
+ SET_GDT_BASE(0); SET_GDT_LIMIT(0);
+
+ SET_LDT_SELECTOR(0); SET_LDT_BASE(0); SET_LDT_LIMIT(0);
+
+ SET_TR_SELECTOR(0); SET_TR_BASE(0); SET_TR_LIMIT(0);
+ SET_TR_AR_SUPER(3);
+
+ SET_EAX(0);
+ SET_ECX(0); /* Really Undefined */
+#ifdef SPC486
+ SET_EDX(0x0000E401); /* Give component ID : revision ID */
+#else
+ SET_EDX(0x00000303); /* Give component ID : revision ID */
+#endif
+ SET_EBX(0); /* Really Undefined */
+ SET_ESP(0); /* Really Undefined */
+ SET_EBP(0); /* Really Undefined */
+ SET_ESI(0); /* Really Undefined */
+ SET_EDI(0); /* Really Undefined */
+
+
+#if defined(SWITCHNPX)
+ if (!config_inquire(C_SWITCHNPX, NULL))
+ disableNpx = TRUE;
+#endif /* SWITCHNPX */
+
+ if ( disableNpx )
+ SET_ET(0);
+ else
+ SET_ET(1);
+
+ InitNpx(disableNpx);
+ }
+
+
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Entry point to CPU. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_simulate IFN0()
+ {
+ SYNCH_TICK();
+ if (simulate_level >= FRAMES)
+ fprintf(stderr, "Stack overflow in host_simulate()!\n");
+
+ /* Save current context and invoke a new CPU level */
+#ifdef NTVDM
+ if ( setjmp(ccpu386SimulatePtr()) == 0)
+#else
+ if ( setjmp(longjmp_env_stack[simulate_level++]) == 0 )
+#endif
+ {
+ in_C = 0;
+ ccpu(FALSE);
+ }
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Restart (Continue) point for CPU. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_continue IFN0()
+ {
+#ifdef NTVDM
+ ccpu386GotoThrdExptnPt();
+#else
+ longjmp(next_inst[simulate_level-1], 1);
+#endif
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* Exit point from CPU. */
+ /* Called from CPU via 'BOP FE' to exit the current CPU invocation */
+ /* Or from CPU via '0F 0F' for the PIG_TESTER. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_unsimulate IFN0()
+ {
+#ifdef NTVDM
+ ccpu386Unsimulate();
+#else
+ if (simulate_level == 0)
+ {
+ fprintf(stderr, "host_unsimulate() - already at base of stack!\n");
+#ifndef PROD
+ force_yoda();
+#endif /* PROD */
+ }
+ else
+ {
+ /* Return to previous context */
+ in_C = 1;
+ longjmp(longjmp_env_stack[--simulate_level], 1);
+ }
+#endif
+ }
+
+#ifdef PIG
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* To push an interrupt frame in response to an external interrupt. */
+ /* Called from CPU under test, just before it processes the interrupt */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_pig_interrupt
+ IFN1(
+ IU8, vector
+ )
+
+ {
+ if (simulate_level >= FRAMES)
+ fprintf(stderr, "Stack overflow in c_do_interrupt()!\n");
+
+ /* Save current context and invoke a new CPU level */
+#ifdef NTVDM
+ if ( setjmp(ccpu386SimulatePtr()) == 0)
+#else
+ if ( setjmp(longjmp_env_stack[simulate_level++]) == 0 )
+#endif
+ {
+ in_C = 0;
+ EXT = EXTERNAL;
+
+ /* Reset default mode */
+ SET_OPERAND_SIZE(GET_CS_AR_X());
+ SET_ADDRESS_SIZE(GET_CS_AR_X());
+
+ do_intrupt((IU16)vector, FALSE, FALSE, (IU16)0);
+ }
+ }
+#endif /* PIG */
+
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* End of application hook. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_EOA_hook IFN0()
+ {
+ /* Do nothing */
+ }
+
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ /* SoftPC termination hook. */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+ GLOBAL VOID
+ c_cpu_terminate IFN0()
+ {
+ /* Do nothing */
+ }