diff options
Diffstat (limited to 'private/mvdm/softpc.new/base/ccpu386/c_main.c')
-rw-r--r-- | private/mvdm/softpc.new/base/ccpu386/c_main.c | 4940 |
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 */ + } |