Starting work on disambiguating PCjs the emulator from PCjs the project/website; the emulator will become PCx86
This commit is contained in:
parent
7c3aab2a7e
commit
288f28055d
1519 changed files with 16242 additions and 6939 deletions
|
|
@ -1,897 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Defines PCjs x86 constants.
|
||||
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
|
||||
* @version 1.0
|
||||
* Created 2012-Sep-05
|
||||
*
|
||||
* Copyright © 2012-2016 Jeff Parsons <Jeff@pcjs.org>
|
||||
*
|
||||
* This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
|
||||
* at <http://jsmachines.net/> and <http://pcjs.org/>.
|
||||
*
|
||||
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCjs. If not,
|
||||
* see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
* You are required to include the above copyright notice in every source code file of every
|
||||
* copy or modified version of this work, and to display that copyright notice on every screen
|
||||
* that loads or runs any version of this software (see Computer.COPYRIGHT).
|
||||
*
|
||||
* Some PCjs files also attempt to load external resource files, such as character-image files,
|
||||
* ROM files, and disk image files. Those external resource files are not considered part of the
|
||||
* PCjs program for purposes of the GNU General Public License, and the author does not claim
|
||||
* any copyright as to their contents.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var X86 = {
|
||||
/*
|
||||
* CPU model numbers (supported)
|
||||
*/
|
||||
MODEL_8086: 8086,
|
||||
MODEL_8088: 8088,
|
||||
MODEL_80186: 80186,
|
||||
MODEL_80188: 80188,
|
||||
MODEL_80286: 80286,
|
||||
MODEL_80386: 80386,
|
||||
|
||||
/*
|
||||
* 80386 CPU stepping identifiers (supported)
|
||||
*/
|
||||
STEPPING_80386_A0: (80386+0xA0), // we have very little information about this stepping...
|
||||
STEPPING_80386_A1: (80386+0xA1), // we know much more about the A1 stepping (see /blog/2015/02/23/README.md)
|
||||
STEPPING_80386_B0: (80386+0xB0), // for now, the only B0 difference in PCjs is support for XBTS and IBTS
|
||||
STEPPING_80386_B1: (80386+0xB1), // our implementation of the B1 stepping also includes the infamous 32-bit multiplication bug
|
||||
STEPPING_80386_B2: (80386+0xB2), // this is an imaginary stepping that simply means "B1 without the 32-bit multiplication bug" (ie, a B1 with the "double sigma" stamp)
|
||||
STEPPING_80386_C0: (80386+0xC0), // this presumably fixed lots of B1 issues, but it seems to have been quickly superseded by the D0
|
||||
STEPPING_80386_D0: (80386+0xD0), // we don't have any detailed information (eg, errata) for these later steppings
|
||||
STEPPING_80386_D1: (80386+0xD1),
|
||||
STEPPING_80386_D2: (80386+0xD2),
|
||||
|
||||
/*
|
||||
* This constant is used to mark points in the code where the physical address being returned
|
||||
* is invalid and should not be used. TODO: There are still functions that will use an invalid
|
||||
* address, which is why we've tried to choose a value that causes the least harm, but ultimately,
|
||||
* we must add checks to those functions or throw special JavaScript exceptions to bypass them.
|
||||
*
|
||||
* This value is also used to indicate non-existent EA address calculations, which are usually
|
||||
* detected with "regEA === ADDR_INVALID" and "regEAWrite === ADDR_INVALID" tests. In a 32-bit
|
||||
* CPU, -1 (ie, 0xffffffff) could actually be a valid address, so consider changing ADDR_INVALID
|
||||
* to NaN or null (which is also why all ADDR_INVALID tests should use strict equality operators).
|
||||
*
|
||||
* The main reason I'm NOT using NaN or null now is my concern that, by mixing non-numbers
|
||||
* (specifically, values outside the range of signed 32-bit integers), performance may suffer.
|
||||
*
|
||||
* WARNING: Like many of the properties defined here, ADDR_INVALID is a common constant, which the
|
||||
* Closure Compiler will happily inline (with or without @const annotations; in fact, I've yet to
|
||||
* see a @const annotation EVER improve automatic inlining). However, if you don't make ABSOLUTELY
|
||||
* certain that this file is included BEFORE the first reference to any of these properties, that
|
||||
* automatic inlining will no longer occur.
|
||||
*/
|
||||
ADDR_INVALID: -1,
|
||||
|
||||
/*
|
||||
* Processor Exception Interrupts
|
||||
*
|
||||
* Of the following exceptions, all are designed to be restartable, except for 0x08 and 0x09 (and 0x0D
|
||||
* after an attempt to write to a read-only segment).
|
||||
*
|
||||
* Error codes are pushed onto the stack for 0x08 (always 0) and 0x0A through 0x0E.
|
||||
*
|
||||
* Priority: Instruction exception, TRAP, NMI, Processor Extension Segment Overrun, and finally INTR.
|
||||
*
|
||||
* All exceptions can also occur in real-mode, except where noted. A GP_FAULT in real-mode can be triggered
|
||||
* by "any memory reference instruction that attempts to reference [a] 16-bit word at offset 0xFFFF".
|
||||
*
|
||||
* Interrupts beyond 0x10 (up through 0x1F) are reserved for future exceptions.
|
||||
*
|
||||
* Implementation Detail: For any opcode we know must generate a UD_FAULT interrupt, we invoke opInvalid(),
|
||||
* NOT opUndefined(). UD_FAULT is for INVALID opcodes, Intel's choice of term "undefined" notwithstanding.
|
||||
*
|
||||
* We reserve the term "undefined" for opcodes that require more investigation, and we invoke opUndefined()
|
||||
* ONLY until an opcode's behavior has finally been defined, at which point it becomes either valid or invalid.
|
||||
* The term "illegal" seems completely superfluous; we don't need a third way of describing invalid opcodes.
|
||||
*
|
||||
* The term "undocumented" should be limited to operations that are valid but Intel simply never documented.
|
||||
*/
|
||||
EXCEPTION: {
|
||||
DE_EXC: 0x00, // Divide Error Exception (#DE: fault, no error code)
|
||||
DB_EXC: 0x01, // Debug (aka Single Step Trap) Exception (#DB: fault or trap)
|
||||
NMI: 0x02, // Non-Maskable Interrupt
|
||||
BP_TRAP: 0x03, // Breakpoint Exception (#BP: trap)
|
||||
OF_TRAP: 0x04, // INTO Overflow Exception (#OF: trap)
|
||||
BR_FAULT: 0x05, // BOUND Error Exception (#BR: fault, no error code)
|
||||
UD_FAULT: 0x06, // Invalid (aka Undefined/Illegal) Opcode (#UD: fault, no error code)
|
||||
NM_FAULT: 0x07, // No Math Unit Available; see ESC or WAIT (#NM: fault, no error code)
|
||||
DF_FAULT: 0x08, // Double Fault; see LIDT (#DF: fault, with error code)
|
||||
MP_FAULT: 0x09, // Math Unit Protection Fault; see ESC (#MP: fault, no error code)
|
||||
TS_FAULT: 0x0A, // Invalid Task State Segment Fault (#TS: fault, with error code; protected-mode only)
|
||||
NP_FAULT: 0x0B, // Not Present Fault (#NP: fault, with error code; protected-mode only)
|
||||
SS_FAULT: 0x0C, // Stack Fault (#SS: fault, with error code; protected-mode only)
|
||||
GP_FAULT: 0x0D, // General Protection Fault (#GP: fault, with error code)
|
||||
PF_FAULT: 0x0E, // Page Fault (#PF: fault, with error code)
|
||||
MF_FAULT: 0x10 // Math Fault; see ESC or WAIT (#MF: fault, no error code)
|
||||
},
|
||||
/*
|
||||
* Processor Status flag definitions (stored in regPS)
|
||||
*/
|
||||
PS: {
|
||||
CF: 0x0001, // bit 0: Carry flag
|
||||
BIT1: 0x0002, // bit 1: reserved, always set
|
||||
PF: 0x0004, // bit 2: Parity flag
|
||||
BIT3: 0x0008, // bit 3: reserved, always clear
|
||||
AF: 0x0010, // bit 4: Auxiliary Carry flag (aka Arithmetic flag)
|
||||
BIT5: 0x0020, // bit 5: reserved, always clear
|
||||
ZF: 0x0040, // bit 6: Zero flag
|
||||
SF: 0x0080, // bit 7: Sign flag
|
||||
TF: 0x0100, // bit 8: Trap flag
|
||||
IF: 0x0200, // bit 9: Interrupt flag
|
||||
DF: 0x0400, // bit 10: Direction flag
|
||||
OF: 0x0800, // bit 11: Overflow flag
|
||||
IOPL: {
|
||||
MASK: 0x3000, // bits 12-13: I/O Privilege Level (always set on 8086/80186; clear on 80286 reset)
|
||||
SHIFT: 12
|
||||
},
|
||||
NT: 0x4000, // bit 14: Nested Task flag (always set on 8086/80186; clear on 80286 reset)
|
||||
BIT15: 0x8000, // bit 15: reserved (always set on 8086/80186; clear otherwise)
|
||||
RF: 0x10000, // bit 16: Resume Flag (temporarily disables debug exceptions; 80386 only)
|
||||
VM: 0x20000 // bit 17: Virtual 8086 Mode (80386 only)
|
||||
},
|
||||
CR0: {
|
||||
/*
|
||||
* Machine Status Word (MSW) bit definitions
|
||||
*/
|
||||
MSW: {
|
||||
PE: 0x0001, // protected-mode enabled
|
||||
MP: 0x0002, // monitor processor extension (ie, coprocessor)
|
||||
EM: 0x0004, // emulate processor extension
|
||||
TS: 0x0008, // task switch indicator
|
||||
ON: 0xFFF0, // on the 80286, these bits are always on (TODO: Verify)
|
||||
MASK: 0xFFFF // these are the only (MSW) bits that the 80286 can access (within CR0)
|
||||
},
|
||||
ET: 0x00000010, // coprocessor type (80287 or 80387); always 1 on post-80386 CPUs
|
||||
PG: 0x80000000|0 // 0: paging disabled
|
||||
},
|
||||
DR7: { // Debug Control Register
|
||||
L0: 0x00000001,
|
||||
G0: 0x00000002,
|
||||
L1: 0x00000004,
|
||||
G1: 0x00000008,
|
||||
L2: 0x00000010,
|
||||
G2: 0x00000020,
|
||||
L3: 0x00000040,
|
||||
G3: 0x00000080,
|
||||
ENABLE: 0x000000FF,
|
||||
LE: 0x00000100,
|
||||
GE: 0x00000200,
|
||||
RW0: 0x00030000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN0: 0x000C0000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW1: 0x00300000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN1: 0x00C00000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW2: 0x03000000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN2: 0x0C000000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW3: 0x30000000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN3: 0xC0000000|0// 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
},
|
||||
DR6: { // Debug Status Register
|
||||
B0: 0x00000001,
|
||||
B1: 0x00000002,
|
||||
B2: 0x00000004,
|
||||
B3: 0x00000008,
|
||||
BD: 0x00002000, // set if the next instruction will read or write one of the eight debug registers and ICE-386 is also using them
|
||||
BS: 0x00004000, // set if the debug handler is entered due to the TF (trap flag) bit set in the EFLAGS register
|
||||
BT: 0x00008000 // set before entering the DEBUG handler if a task switch has occurred and the T-bit of the new TSS is set
|
||||
},
|
||||
SEL: {
|
||||
RPL: 0x0003, // requested privilege level (0-3)
|
||||
LDT: 0x0004, // table indicator (0: GDT, 1: LDT)
|
||||
MASK: 0xFFF8 // table offset
|
||||
},
|
||||
DESC: { // Descriptor Table Entry
|
||||
LIMIT: { // LIMIT bits 0-15 (or OFFSET if this is an INTERRUPT or TRAP gate)
|
||||
OFFSET: 0x0
|
||||
},
|
||||
BASE: { // BASE bits 0-15 (or SELECTOR if this is a TASK, INTERRUPT or TRAP gate)
|
||||
OFFSET: 0x2
|
||||
},
|
||||
ACC: { // bit definitions for the access word (offset 0x4)
|
||||
OFFSET: 0x4,
|
||||
BASE1623: 0x00FF, // (not used if this a TASK, INTERRUPT or TRAP gate; bits 0-5 are parm count for CALL gates)
|
||||
TYPE: {
|
||||
OFFSET: 0x5,
|
||||
MASK: 0x1F00,
|
||||
SEG: 0x1000,
|
||||
NONSEG: 0x0F00,
|
||||
/*
|
||||
* The following bits apply only when SEG is set
|
||||
*/
|
||||
CODE: 0x0800, // set for CODE, clear for DATA
|
||||
ACCESSED: 0x0100, // set if accessed, clear if not accessed
|
||||
READABLE: 0x0200, // CODE: set if readable, clear if exec-only
|
||||
WRITABLE: 0x0200, // DATA: set if writable, clear if read-only
|
||||
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
|
||||
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
|
||||
/*
|
||||
* Assorted bits that apply only within NONSEG values
|
||||
*/
|
||||
TSS_BUSY: 0x0200,
|
||||
NONSEG_386: 0x0800, // 80386 and up
|
||||
/*
|
||||
* The following are all the possible (valid) types (well, except for the variations
|
||||
* of DATA and CODE where the ACCESSED bit (0x0100) may also be set)
|
||||
*/
|
||||
TSS286: 0x0100,
|
||||
LDT: 0x0200,
|
||||
TSS286_BUSY: 0x0300,
|
||||
GATE_CALL: 0x0400,
|
||||
GATE_TASK: 0x0500,
|
||||
GATE286_INT: 0x0600,
|
||||
GATE286_TRAP: 0x0700,
|
||||
TSS386: 0x0900, // 80386 and up
|
||||
TSS386_BUSY: 0x0B00, // 80386 and up
|
||||
GATE386_CALL: 0x0C00, // 80386 and up
|
||||
GATE386_INT: 0x0E00, // 80386 and up
|
||||
GATE386_TRAP: 0x0F00, // 80386 and up
|
||||
CODE_OR_DATA: 0x1E00,
|
||||
DATA_READONLY: 0x1000,
|
||||
DATA_WRITABLE: 0x1200,
|
||||
DATA_EXPDOWN: 0x1400,
|
||||
DATA_EXPDOWN_WRITABLE: 0x1600,
|
||||
CODE_EXECONLY: 0x1800,
|
||||
CODE_READABLE: 0x1A00,
|
||||
CODE_CONFORMING: 0x1C00,
|
||||
CODE_CONFORMING_READABLE: 0x1E00
|
||||
},
|
||||
DPL: {
|
||||
MASK: 0x6000,
|
||||
SHIFT: 13
|
||||
},
|
||||
PRESENT: 0x8000,
|
||||
INVALID: 0 // use X86.DESC.ACC.INVALID for invalid ACC values
|
||||
},
|
||||
EXT: { // descriptor extension word (reserved on the 80286; "must be zero")
|
||||
OFFSET: 0x6,
|
||||
LIMIT1619: 0x000F,
|
||||
AVAIL: 0x0010, // NOTE: set in various descriptors in OS/2
|
||||
/*
|
||||
* The BIG bit is known as the D bit for code segments; when set, all addresses and operands
|
||||
* in that code segment are assumed to be 32-bit.
|
||||
*
|
||||
* The BIG bit is known as the B bit for data segments; when set, it indicates: 1) all pushes,
|
||||
* pops, calls and returns use ESP instead of SP, and 2) the upper bound of an expand-down segment
|
||||
* is 0xffffffff instead of 0xffff.
|
||||
*/
|
||||
BIG: 0x0040, // clear if default operand/address size is 16-bit, set if 32-bit
|
||||
LIMITPAGES: 0x0080, // clear if limit granularity is bytes, set if limit granularity is 4Kb pages
|
||||
BASE2431: 0xFF00
|
||||
},
|
||||
INVALID: 0 // use X86.DESC.INVALID for invalid DESC values
|
||||
},
|
||||
LADDR: { // linear address
|
||||
PDE: { // index of page directory entry
|
||||
MASK: 0xFFC00000|0,
|
||||
SHIFT: 20 // (addr & DIR.MASK) >>> DIR.SHIFT yields a page directory offset (ie, index * 4)
|
||||
},
|
||||
PTE: { // index of page table entry
|
||||
MASK: 0x003FF000,
|
||||
SHIFT: 10 // (addr & PAGE.MASK) >>> PAGE.SHIFT yields a page table offset (ie, index * 4)
|
||||
},
|
||||
OFFSET: 0x00000FFF
|
||||
},
|
||||
PTE: {
|
||||
FRAME: 0xFFFFF000|0,
|
||||
DIRTY: 0x00000040, // page has been modified
|
||||
ACCESSED: 0x00000020, // page has been accessed
|
||||
USER: 0x00000004, // set for user level (CPL 3), clear for supervisor level (CPL 0-2)
|
||||
READWRITE: 0x00000002, // set for read/write, clear for read-only (affects CPL 3 only)
|
||||
PRESENT: 0x00000001 // set for present page, clear for not-present page
|
||||
},
|
||||
TSS286: {
|
||||
PREV_TSS: 0x00,
|
||||
CPL0_SP: 0x02, // start of values altered by task switches
|
||||
CPL0_SS: 0x04,
|
||||
CPL1_SP: 0x06,
|
||||
CPL1_SS: 0x08,
|
||||
CPL2_SP: 0x0A,
|
||||
CPL2_SS: 0x0C,
|
||||
TASK_IP: 0x0E,
|
||||
TASK_PS: 0x10,
|
||||
TASK_AX: 0x12,
|
||||
TASK_CX: 0x14,
|
||||
TASK_DX: 0x16,
|
||||
TASK_BX: 0x18,
|
||||
TASK_SP: 0x1A,
|
||||
TASK_BP: 0x1C,
|
||||
TASK_SI: 0x1E,
|
||||
TASK_DI: 0x20,
|
||||
TASK_ES: 0x22,
|
||||
TASK_CS: 0x24,
|
||||
TASK_SS: 0x26,
|
||||
TASK_DS: 0x28, // end of values altered by task switches
|
||||
TASK_LDT: 0x2A
|
||||
},
|
||||
TSS386: {
|
||||
PREV_TSS: 0x00,
|
||||
CPL0_ESP: 0x04, // start of values altered by task switches
|
||||
CPL0_SS: 0x08,
|
||||
CPL1_ESP: 0x0c,
|
||||
CPL1_SS: 0x10,
|
||||
CPL2_ESP: 0x14,
|
||||
CPL2_SS: 0x18,
|
||||
TASK_CR3: 0x1C, // (not in TSS286)
|
||||
TASK_EIP: 0x20,
|
||||
TASK_PS: 0x24,
|
||||
TASK_EAX: 0x28,
|
||||
TASK_ECX: 0x2C,
|
||||
TASK_EDX: 0x30,
|
||||
TASK_EBX: 0x34,
|
||||
TASK_ESP: 0x38,
|
||||
TASK_EBP: 0x3C,
|
||||
TASK_ESI: 0x40,
|
||||
TASK_EDI: 0x44,
|
||||
TASK_ES: 0x48,
|
||||
TASK_CS: 0x4C,
|
||||
TASK_SS: 0x50,
|
||||
TASK_DS: 0x54,
|
||||
TASK_FS: 0x58, // (not in TSS286)
|
||||
TASK_GS: 0x5C, // (not in TSS286) end of values altered by task switches
|
||||
TASK_LDT: 0x60,
|
||||
TASK_IOPM: 0x64 // (not in TSS286)
|
||||
},
|
||||
ERRCODE: {
|
||||
EXT: 0x0001,
|
||||
IDT: 0x0002,
|
||||
LDT: 0x0004,
|
||||
SELMASK: 0xFFFC
|
||||
},
|
||||
RESULT: {
|
||||
/*
|
||||
* Flags were originally computed using 16-bit result registers:
|
||||
*
|
||||
* CF: resultZeroCarry & resultSize (ie, 0x100 or 0x10000)
|
||||
* PF: resultParitySign & 0xff
|
||||
* AF: (resultParitySign ^ resultAuxOverflow) & 0x0010
|
||||
* ZF: resultZeroCarry & (resultSize - 1)
|
||||
* SF: resultParitySign & (resultSize >> 1)
|
||||
* OF: (resultParitySign ^ resultAuxOverflow ^ (resultParitySign >> 1)) & (resultSize >> 1)
|
||||
*
|
||||
* I386 support requires that we now rely on 32-bit result registers:
|
||||
*
|
||||
* resultDst, resultSrc, resultArith, resultLogic and resultType
|
||||
*
|
||||
* and flags are now computed as follows:
|
||||
*
|
||||
* CF: ((resultDst ^ ((resultDst ^ resultSrc) & (resultSrc ^ resultArith))) & resultType)
|
||||
* PF: (resultLogic & 0xff)
|
||||
* AF: ((resultArith ^ (resultDst ^ resultSrc)) & 0x0010)
|
||||
* ZF: (resultLogic & ((resultType - 1) | resultType))
|
||||
* SF: (resultLogic & resultType)
|
||||
* OF: (((resultDst ^ resultArith) & (resultSrc ^ resultArith)) & resultType)
|
||||
*
|
||||
* where resultType contains both a size, which must be one of BYTE (0x80), WORD (0x8000),
|
||||
* or DWORD (0x80000000), along with bits for each of the arithmetic and/or logical flags that
|
||||
* are currently "cached" in the result registers (eg, X86.RESULT.CF for carry, X86.RESULT.OF
|
||||
* for overflow, etc).
|
||||
*
|
||||
* WARNING: Do not confuse these RESULT flag definitions with the PS flag definitions. RESULT
|
||||
* flags are used only as "cached" flag indicators, packed into bits 0-5 of resultType; they do
|
||||
* not match the actual flag bit definitions within the Processor Status (PS) register.
|
||||
*
|
||||
* Arithmetic operations should call:
|
||||
*
|
||||
* setArithResult(dst, src, value, type)
|
||||
* eg:
|
||||
* setArithResult(dst, src, dst+src, X86.RESULT.BYTE | X86.RESULT.ALL)
|
||||
*
|
||||
* and logical operations should call:
|
||||
*
|
||||
* setLogicResult(value, type [, carry [, overflow]])
|
||||
*
|
||||
* Since most logical operations clear both CF and OF, most calls to setLogicResult() can omit the
|
||||
* last two optional parameters.
|
||||
*
|
||||
* The type parameter of these methods indicates both the size of the result (BYTE, WORD or DWORD)
|
||||
* and which of the flags should now be considered "cached" by the result registers. If the previous
|
||||
* resultType specifies any flags not present in the new type parameter, then those flags are
|
||||
* calculated and written to the appropriate regPS bit(s) *before* the result registers are updated.
|
||||
*
|
||||
* Arithmetic operations are assumed to represent an "added" result; if a "subtracted" result is
|
||||
* provided instead (eg, from CMP, DEC, SUB, etc), then setArithResult() must include a 5th parameter
|
||||
* (fSubtract); eg:
|
||||
*
|
||||
* setArithResult(dst, src, dst-src, X86.RESULT.BYTE | X86.RESULT.ALL, true)
|
||||
*
|
||||
* TODO: Consider separating setArithResult() into two functions: setAddResult() and setSubResult().
|
||||
*/
|
||||
BYTE: 0x80, // result is byte value
|
||||
WORD: 0x8000, // result is word value
|
||||
DWORD: 0x80000000|0,
|
||||
TYPE: 0x80008080|0,
|
||||
CF: 0x01, // carry flag is cached
|
||||
PF: 0x02, // parity flag is cached
|
||||
AF: 0x04, // aux carry flag is cached
|
||||
ZF: 0x08, // zero flag is cached
|
||||
SF: 0x10, // sign flag is cached
|
||||
OF: 0x20, // overflow flag is cached
|
||||
ALL: 0x3F, // all result flags are cached
|
||||
LOGIC: 0x1A, // all logical flags are cached; see setLogicResult()
|
||||
NOTCF: 0x3E // all result flags EXCEPT carry are cached
|
||||
},
|
||||
/*
|
||||
* Bit values for opFlags, which are all reset to zero prior to each instruction
|
||||
*/
|
||||
OPFLAG: {
|
||||
NOREAD: 0x0001, // disable memory reads for the remainder of the current instruction
|
||||
NOWRITE: 0x0002, // disable memory writes for the remainder of the current instruction
|
||||
NOINTR: 0x0004, // a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
|
||||
SEG: 0x0010, // segment override
|
||||
LOCK: 0x0020, // lock prefix
|
||||
REPZ: 0x0040, // repeat while Z (NOTE: this value MUST match PS.ZF; see opCMPSb/opCMPSw/opSCASb/opSCASw)
|
||||
REPNZ: 0x0080, // repeat while NZ
|
||||
REPEAT: 0x0100, // an instruction is being repeated (ie, some iteration AFTER the first)
|
||||
PUSHSP: 0x0200, // the SP register is potentially being referenced by a PUSH SP opcode, adjustment may be required
|
||||
DATASIZE: 0x0400, // data size override
|
||||
ADDRSIZE: 0x0800, // address size override
|
||||
FAULT: 0x1000, // a fault occurred during the current instruction
|
||||
DBEXC: 0x2000 // a DB_EXC exception occurred during the current instruction
|
||||
},
|
||||
/*
|
||||
* Bit values for intFlags
|
||||
*/
|
||||
INTFLAG: {
|
||||
NONE: 0x00,
|
||||
INTR: 0x01, // h/w interrupt requested
|
||||
TRAP: 0x02, // trap (INT 0x01) requested
|
||||
HALT: 0x04, // halt (HLT) requested
|
||||
DMA: 0x08 // async DMA operation in progress
|
||||
},
|
||||
/*
|
||||
* Common opcodes (and/or any opcodes we need to refer to explicitly)
|
||||
*/
|
||||
OPCODE: {
|
||||
ES: 0x26, // opES()
|
||||
CS: 0x2E, // opCS()
|
||||
SS: 0x36, // opSS()
|
||||
DS: 0x3E, // opDS()
|
||||
PUSHSP: 0x54, // opPUSHSP()
|
||||
PUSHA: 0x60, // opPUSHA() (80186 and up)
|
||||
POPA: 0x61, // opPOPA() (80186 and up)
|
||||
BOUND: 0x62, // opBOUND() (80186 and up)
|
||||
ARPL: 0x63, // opARPL() (80286 and up)
|
||||
FS: 0x64, // opFS() (80386 and up)
|
||||
GS: 0x65, // opGS() (80386 and up)
|
||||
OS: 0x66, // opOS() (80386 and up)
|
||||
AS: 0x67, // opAS() (80386 and up)
|
||||
PUSHN: 0x68, // opPUSHn() (80186 and up)
|
||||
IMULN: 0x69, // opIMULn() (80186 and up)
|
||||
PUSH8: 0x6A, // opPUSH8() (80186 and up)
|
||||
IMUL8: 0x6B, // opIMUL8() (80186 and up)
|
||||
INSB: 0x6C, // opINSb() (80186 and up)
|
||||
INSW: 0x6D, // opINSw() (80186 and up)
|
||||
OUTSB: 0x6E, // opOUTSb() (80186 and up)
|
||||
OUTSW: 0x6F, // opOUTSw() (80186 and up)
|
||||
ENTER: 0xC8, // opENTER() (80186 and up)
|
||||
LEAVE: 0xC9, // opLEAVE() (80186 and up)
|
||||
CALLF: 0x9A, // opCALLF()
|
||||
MOVSB: 0xA4, // opMOVSb()
|
||||
MOVSW: 0xA5, // opMOVSw()
|
||||
CMPSB: 0xA6, // opCMPSb()
|
||||
CMPSW: 0xA7, // opCMPSw()
|
||||
STOSB: 0xAA, // opSTOSb()
|
||||
STOSW: 0xAB, // opSTOSw()
|
||||
LODSB: 0xAC, // opLODSb()
|
||||
LODSW: 0xAD, // opLODSw()
|
||||
SCASB: 0xAE, // opSCASb()
|
||||
SCASW: 0xAF, // opSCASw()
|
||||
INT3: 0xCC, // opINT3()
|
||||
INTN: 0xCD, // opINTn()
|
||||
INTO: 0xCE, // opINTO()
|
||||
IRET: 0xCF, // opIRET()
|
||||
ESC0: 0xD8, // opESC0()
|
||||
ESC1: 0xD9, // opESC1()
|
||||
ESC2: 0xDA, // opESC2()
|
||||
ESC3: 0xDB, // opESC3()
|
||||
ESC4: 0xDC, // opESC4()
|
||||
ESC5: 0xDD, // opESC5()
|
||||
ESC6: 0xDE, // opESC6()
|
||||
ESC7: 0xDF, // opESC7()
|
||||
LOOPNZ: 0xE0, // opLOOPNZ()
|
||||
LOOPZ: 0xE1, // opLOOPZ()
|
||||
LOOP: 0xE2, // opLOOP()
|
||||
CALL: 0xE8, // opCALL()
|
||||
JMP: 0xE9, // opJMP() (2-byte displacement)
|
||||
JMPF: 0xEA, // opJMPF()
|
||||
JMPS: 0xEB, // opJMPs() (1-byte displacement)
|
||||
LOCK: 0xF0, // opLOCK()
|
||||
REPNZ: 0xF2, // opREPNZ()
|
||||
REPZ: 0xF3, // opREPZ()
|
||||
GRP4W: 0xFF,
|
||||
CALLW: 0x10FF, // GRP4W: fnCALLw()
|
||||
CALLFDW: 0x18FF, // GRP4W: fnCALLFdw()
|
||||
CALLMASK: 0x38FF, // mask 2-byte GRP4W opcodes with this before comparing to CALLW or CALLFDW
|
||||
UD2: 0x0B0F // UD2 (invalid opcode "guaranteed" to generate UD_FAULT on all post-8086 processors)
|
||||
},
|
||||
/*
|
||||
* Floating Point Unit (FPU), aka Numeric Data Processor (NDP), aka Numeric Processor Extension (NPX), aka Coprocessor definitions
|
||||
*/
|
||||
FPU: {
|
||||
MODEL_8087: 8087,
|
||||
MODEL_80287: 80287,
|
||||
MODEL_80287XL: 80387, // internally, the 80287XL was an 80387SX, so generally, we treat this as MODEL_80387
|
||||
MODEL_80387: 80387,
|
||||
CONTROL: { // FPU Control Word
|
||||
IM: 0x0001, // bit 0: Invalid Operation Mask
|
||||
DM: 0x0002, // bit 1: Denormalized Operand Mask
|
||||
ZM: 0x0004, // bit 2: Zero Divide Mask
|
||||
OM: 0x0008, // bit 3: Overflow Mask
|
||||
UM: 0x0010, // bit 4: Underflow Mask
|
||||
PM: 0x0020, // bit 5: Precision Mask
|
||||
EXC: 0x003F, // all of the above exceptions
|
||||
IEM: 0x0080, // bit 7: Interrupt Enable Mask (0 enables interrupts, 1 masks them; 8087 only)
|
||||
PC: 0x0300, // bits 8-9: Precision Control
|
||||
RC: { // bits 10-11: Rounding Control
|
||||
NEAR: 0x0000,
|
||||
DOWN: 0x0400,
|
||||
UP: 0x0800,
|
||||
CHOP: 0x0C00,
|
||||
MASK: 0x0C00
|
||||
},
|
||||
IC: 0x1000, // bit 12: Infinity Control (0 for Projective, 1 for Affine)
|
||||
UNUSED: 0xE040, // bits 6,13-15: unused
|
||||
INIT: 0x03BF // X86.FPU.CONTROL.IM | X86.FPU.CONTROL.DM | X86.FPU.CONTROL.ZM | X86.FPU.CONTROL.OM | X86.FPU.CONTROL.UM | X86.FPU.CONTROL.PM | X86.FPU.CONTROL.IEM | X86.FPU.CONTROL.PC
|
||||
},
|
||||
STATUS: { // FPU Status Word
|
||||
IE: 0x0001, // bit 0: Invalid Operation
|
||||
DE: 0x0002, // bit 1: Denormalized Operand
|
||||
ZE: 0x0004, // bit 2: Zero Divide
|
||||
OE: 0x0008, // bit 3: Overflow
|
||||
UE: 0x0010, // bit 4: Underflow
|
||||
PE: 0x0020, // bit 5: Precision
|
||||
SF: 0x0040, // bit 6: Stack Fault (80387 and later; triggers an Invalid Operation exception)
|
||||
EXC: 0x007F, // all of the above exceptions
|
||||
ES: 0x0080, // bit 7: Error/Exception Status/Summary (Interrupt Request on 8087)
|
||||
C0: 0x0100, // bit 8: Condition Code 0
|
||||
C1: 0x0200, // bit 9: Condition Code 1
|
||||
C2: 0x0400, // bit 10: Condition Code 2
|
||||
ST: 0x3800, // bits 11-13: Stack Top
|
||||
ST_SHIFT: 11,
|
||||
C3: 0x4000, // bit 14: Condition Code 3
|
||||
CC: 0x4700, // all condition code bits
|
||||
BUSY: 0x8000 // bit 15: Busy
|
||||
},
|
||||
TAGS: {
|
||||
VALID: 0x0,
|
||||
ZERO: 0x1,
|
||||
SPECIAL:0x2,
|
||||
EMPTY: 0x3,
|
||||
MASK: 0x3
|
||||
}
|
||||
/*
|
||||
C3 C2 C1 C0 Condition Code (CC) values following an Examine
|
||||
|
||||
0 0 0 0 Valid, positive unnormalized (+Unnormal)
|
||||
0 0 0 1 Invalid, positive, exponent=0 (+NaN)
|
||||
0 0 1 0 Valid, negative, unnormalized (-Unnormal)
|
||||
0 0 1 1 Invalid, negative, exponent=0 (-NaN)
|
||||
0 1 0 0 Valid, positive, normalized (+Normal)
|
||||
0 1 0 1 Infinity, positive (+Infinity)
|
||||
0 1 1 0 Valid, negative, normalized (-Normal)
|
||||
0 1 1 1 Infinity, negative (-Infinity)
|
||||
1 0 0 0 Zero, positive (+0)
|
||||
1 0 0 1 Empty
|
||||
1 0 1 0 Zero, negative (-0)
|
||||
1 0 1 1 Empty
|
||||
1 1 0 0 Invalid, positive, exponent=0 (+Denormal)
|
||||
1 1 0 1 Empty
|
||||
1 1 1 0 Invalid, negative, exponent=0 (-Denormal)
|
||||
1 1 1 1 Empty
|
||||
|
||||
Condition Code (CC) values following an FCOM or FTST
|
||||
|
||||
0 0 ? 0 ST > source operand (FCOM); ST > 0 (FTST)
|
||||
0 0 ? 1 ST < source operand (FCOM); ST < 0 (FTST)
|
||||
1 0 ? 0 ST = source operand (FCOM); ST = 0 (FTST)
|
||||
1 1 ? 1 ST is not comparable
|
||||
|
||||
Condition Code (CC) values following a Remainder
|
||||
|
||||
Q1 0 Q0 Q2 Complete reduction (he three low bits of the quotient stored in C0, C3, and C1)
|
||||
? 1 ? ? Incomplete reduction
|
||||
*/
|
||||
},
|
||||
CYCLES_8088: {
|
||||
nWordCyclePenalty: 4, // NOTE: accurate for the 8088/80188 only (on the 8086/80186, it applies to odd addresses only)
|
||||
nEACyclesBase: 5, // base or index only (BX, BP, SI or DI)
|
||||
nEACyclesDisp: 6, // displacement only
|
||||
nEACyclesBaseIndex: 7, // base + index (BP+DI and BX+SI)
|
||||
nEACyclesBaseIndexExtra: 8, // base + index (BP+SI and BX+DI require an extra cycle)
|
||||
nEACyclesBaseDisp: 9, // base or index + displacement
|
||||
nEACyclesBaseIndexDisp: 11, // base + index + displacement (BP+DI+n and BX+SI+n)
|
||||
nEACyclesBaseIndexDispExtra:12, // base + index + displacement (BP+SI+n and BX+DI+n require an extra cycle)
|
||||
nOpCyclesAAA: 4, // AAA, AAS, DAA, DAS, TEST acc,imm
|
||||
nOpCyclesAAD: 60,
|
||||
nOpCyclesAAM: 83,
|
||||
nOpCyclesArithRR: 3, // ADC, ADD, AND, OR, SBB, SUB, XOR and CMP reg,reg cycle time
|
||||
nOpCyclesArithRM: 9, // ADC, ADD, AND, OR, SBB, SUB, and XOR reg,mem (and CMP mem,reg) cycle time
|
||||
nOpCyclesArithMR: 16, // ADC, ADD, AND, OR, SBB, SUB, and XOR mem,reg cycle time
|
||||
nOpCyclesArithMID: 1, // ADC, ADD, AND, OR, SBB, SUB, XOR and CMP mem,imm cycle delta
|
||||
nOpCyclesCall: 19,
|
||||
nOpCyclesCallF: 28,
|
||||
nOpCyclesCallWR: 16,
|
||||
nOpCyclesCallWM: 21,
|
||||
nOpCyclesCallDM: 37,
|
||||
nOpCyclesCLI: 2,
|
||||
nOpCyclesCompareRM: 9, // CMP reg,mem cycle time (same as nOpCyclesArithRM on an 8086 but not on a 80286)
|
||||
nOpCyclesCWD: 5,
|
||||
nOpCyclesBound: 33, // N/A if 8086/8088, 33-35 if 80186/80188 (TODO: Determine what the range means for an 80186/80188)
|
||||
nOpCyclesInP: 10,
|
||||
nOpCyclesInDX: 8,
|
||||
nOpCyclesIncR: 3, // INC reg, DEC reg
|
||||
nOpCyclesIncM: 15, // INC mem, DEC mem
|
||||
nOpCyclesInt: 51,
|
||||
nOpCyclesInt3D: 1,
|
||||
nOpCyclesIntOD: 2,
|
||||
nOpCyclesIntOFall: 4,
|
||||
nOpCyclesIRet: 32,
|
||||
nOpCyclesJmp: 15,
|
||||
nOpCyclesJmpF: 15,
|
||||
nOpCyclesJmpC: 16,
|
||||
nOpCyclesJmpCFall: 4,
|
||||
nOpCyclesJmpWR: 11,
|
||||
nOpCyclesJmpWM: 18,
|
||||
nOpCyclesJmpDM: 24,
|
||||
nOpCyclesLAHF: 4, // LAHF, SAHF, MOV reg,imm
|
||||
nOpCyclesLEA: 2,
|
||||
nOpCyclesLS: 16, // LDS, LES
|
||||
nOpCyclesLoop: 17, // LOOP, LOOPNZ
|
||||
nOpCyclesLoopZ: 18, // LOOPZ, JCXZ
|
||||
nOpCyclesLoopNZ: 19, // LOOPNZ
|
||||
nOpCyclesLoopFall: 5, // LOOP
|
||||
nOpCyclesLoopZFall: 6, // LOOPZ, JCXZ
|
||||
nOpCyclesMovRR: 2,
|
||||
nOpCyclesMovRM: 8,
|
||||
nOpCyclesMovMR: 9,
|
||||
nOpCyclesMovRI: 10,
|
||||
nOpCyclesMovMI: 10,
|
||||
nOpCyclesMovAM: 10,
|
||||
nOpCyclesMovMA: 10,
|
||||
nOpCyclesDivBR: 80, // range of 80-90
|
||||
nOpCyclesDivWR: 144, // range of 144-162
|
||||
nOpCyclesDivBM: 86, // range of 86-96
|
||||
nOpCyclesDivWM: 154, // range of 154-172
|
||||
nOpCyclesIDivBR: 101, // range of 101-112
|
||||
nOpCyclesIDivWR: 165, // range of 165-184
|
||||
nOpCyclesIDivBM: 107, // range of 107-118
|
||||
nOpCyclesIDivWM: 171, // range of 171-190
|
||||
nOpCyclesMulBR: 70, // range of 70-77
|
||||
nOpCyclesMulWR: 113, // range of 113-118
|
||||
nOpCyclesMulBM: 76, // range of 76-83
|
||||
nOpCyclesMulWM: 124, // range of 124-139
|
||||
nOpCyclesIMulBR: 80, // range of 80-98
|
||||
nOpCyclesIMulWR: 128, // range of 128-154
|
||||
nOpCyclesIMulBM: 86, // range of 86-104
|
||||
nOpCyclesIMulWM: 134, // range of 134-160
|
||||
nOpCyclesNegR: 3, // NEG reg, NOT reg
|
||||
nOpCyclesNegM: 16, // NEG mem, NOT mem
|
||||
nOpCyclesOutP: 10,
|
||||
nOpCyclesOutDX: 8,
|
||||
nOpCyclesPopAll: 51, // N/A if 8086/8088, 51 if 80186, 83 if 80188 (TODO: Verify)
|
||||
nOpCyclesPopReg: 8,
|
||||
nOpCyclesPopMem: 17,
|
||||
nOpCyclesPushAll: 36, // N/A if 8086/8088, 36 if 80186, 68 if 80188 (TODO: Verify)
|
||||
nOpCyclesPushReg: 11, // NOTE: "The 8086 Book" claims this is 10, but it's an outlier....
|
||||
nOpCyclesPushMem: 16,
|
||||
nOpCyclesPushSeg: 10,
|
||||
nOpCyclesPrefix: 2,
|
||||
nOpCyclesCmpS: 18,
|
||||
nOpCyclesCmpSr0: 9-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesCmpSrn: 17-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesLodS: 12,
|
||||
nOpCyclesLodSr0: 9-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesLodSrn: 13-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesMovS: 18,
|
||||
nOpCyclesMovSr0: 9-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesMovSrn: 17-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesScaS: 15,
|
||||
nOpCyclesScaSr0: 9-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesScaSrn: 15-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesStoS: 11,
|
||||
nOpCyclesStoSr0: 9-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesStoSrn: 10-2, // reduced by nOpCyclesPrefix
|
||||
nOpCyclesRet: 8,
|
||||
nOpCyclesRetn: 12,
|
||||
nOpCyclesRetF: 18,
|
||||
nOpCyclesRetFn: 17,
|
||||
nOpCyclesShift1M: 15, // ROL/ROR/RCL/RCR/SHL/SHR/SAR reg,1
|
||||
nOpCyclesShiftCR: 8, // ROL/ROR/RCL/RCR/SHL/SHR/SAR reg,CL
|
||||
nOpCyclesShiftCM: 20, // ROL/ROR/RCL/RCR/SHL/SHR/SAR mem,CL
|
||||
nOpCyclesShiftCS: 2, // this is the left-shift value used to convert the count to the cycle cost
|
||||
nOpCyclesTestRR: 3,
|
||||
nOpCyclesTestRM: 9,
|
||||
nOpCyclesTestRI: 5,
|
||||
nOpCyclesTestMI: 11,
|
||||
nOpCyclesXchgRR: 4,
|
||||
nOpCyclesXchgRM: 17,
|
||||
nOpCyclesXLAT: 11
|
||||
},
|
||||
CYCLES_80286: {
|
||||
nWordCyclePenalty: 0,
|
||||
nEACyclesBase: 0,
|
||||
nEACyclesDisp: 0,
|
||||
nEACyclesBaseIndex: 0,
|
||||
nEACyclesBaseIndexExtra: 0,
|
||||
nEACyclesBaseDisp: 0,
|
||||
nEACyclesBaseIndexDisp: 1,
|
||||
nEACyclesBaseIndexDispExtra:1,
|
||||
nOpCyclesAAA: 3,
|
||||
nOpCyclesAAD: 14,
|
||||
nOpCyclesAAM: 16,
|
||||
nOpCyclesArithRR: 2,
|
||||
nOpCyclesArithRM: 7,
|
||||
nOpCyclesArithMR: 7,
|
||||
nOpCyclesArithMID: 0,
|
||||
nOpCyclesCall: 7, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesCallF: 13, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesCallWR: 7, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesCallWM: 11, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesCallDM: 16, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesCLI: 3,
|
||||
nOpCyclesCompareRM: 6,
|
||||
nOpCyclesCWD: 2,
|
||||
nOpCyclesBound: 13,
|
||||
nOpCyclesInP: 5,
|
||||
nOpCyclesInDX: 5,
|
||||
nOpCyclesIncR: 2,
|
||||
nOpCyclesIncM: 7,
|
||||
nOpCyclesInt: 23, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesInt3D: 0,
|
||||
nOpCyclesIntOD: 1,
|
||||
nOpCyclesIntOFall: 3,
|
||||
nOpCyclesIRet: 17, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmp: 7, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmpF: 11, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmpC: 7, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmpCFall: 3,
|
||||
nOpCyclesJmpWR: 7, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmpWM: 11, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesJmpDM: 15, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesLAHF: 2,
|
||||
nOpCyclesLEA: 3,
|
||||
nOpCyclesLS: 7,
|
||||
nOpCyclesLoop: 8, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesLoopZ: 8, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesLoopNZ: 8, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesLoopFall: 4,
|
||||
nOpCyclesLoopZFall: 4,
|
||||
nOpCyclesMovRR: 2, // this is actually the same as the 8086...
|
||||
nOpCyclesMovRM: 3,
|
||||
nOpCyclesMovMR: 5,
|
||||
nOpCyclesMovRI: 2,
|
||||
nOpCyclesMovMI: 3,
|
||||
nOpCyclesMovAM: 5, // this is actually slower than the MOD/RM form of MOV AX,mem (see nOpCyclesMovRM)
|
||||
nOpCyclesMovMA: 3,
|
||||
nOpCyclesDivBR: 14,
|
||||
nOpCyclesDivWR: 22,
|
||||
nOpCyclesDivBM: 17,
|
||||
nOpCyclesDivWM: 25,
|
||||
nOpCyclesIDivBR: 17,
|
||||
nOpCyclesIDivWR: 25,
|
||||
nOpCyclesIDivBM: 20,
|
||||
nOpCyclesIDivWM: 28,
|
||||
nOpCyclesMulBR: 13,
|
||||
nOpCyclesMulWR: 21,
|
||||
nOpCyclesMulBM: 16,
|
||||
nOpCyclesMulWM: 24,
|
||||
nOpCyclesIMulBR: 13,
|
||||
nOpCyclesIMulWR: 21,
|
||||
nOpCyclesIMulBM: 16,
|
||||
nOpCyclesIMulWM: 24,
|
||||
nOpCyclesNegR: 2,
|
||||
nOpCyclesNegM: 7,
|
||||
nOpCyclesOutP: 5,
|
||||
nOpCyclesOutDX: 5,
|
||||
nOpCyclesPopAll: 19,
|
||||
nOpCyclesPopReg: 5,
|
||||
nOpCyclesPopMem: 5,
|
||||
nOpCyclesPushAll: 17,
|
||||
nOpCyclesPushReg: 3,
|
||||
nOpCyclesPushMem: 5,
|
||||
nOpCyclesPushSeg: 3,
|
||||
nOpCyclesPrefix: 0,
|
||||
nOpCyclesCmpS: 8,
|
||||
nOpCyclesCmpSr0: 5,
|
||||
nOpCyclesCmpSrn: 9,
|
||||
nOpCyclesLodS: 5,
|
||||
nOpCyclesLodSr0: 5,
|
||||
nOpCyclesLodSrn: 4,
|
||||
nOpCyclesMovS: 5,
|
||||
nOpCyclesMovSr0: 5,
|
||||
nOpCyclesMovSrn: 4,
|
||||
nOpCyclesScaS: 7,
|
||||
nOpCyclesScaSr0: 5,
|
||||
nOpCyclesScaSrn: 8,
|
||||
nOpCyclesStoS: 3,
|
||||
nOpCyclesStoSr0: 4,
|
||||
nOpCyclesStoSrn: 3,
|
||||
nOpCyclesRet: 11, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesRetn: 11, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesRetF: 15, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesRetFn: 15, // on the 80286, this ALSO includes the number of bytes in the target instruction
|
||||
nOpCyclesShift1M: 7,
|
||||
nOpCyclesShiftCR: 5,
|
||||
nOpCyclesShiftCM: 8,
|
||||
nOpCyclesShiftCS: 0,
|
||||
nOpCyclesTestRR: 2,
|
||||
nOpCyclesTestRM: 6,
|
||||
nOpCyclesTestRI: 3,
|
||||
nOpCyclesTestMI: 6,
|
||||
nOpCyclesXchgRR: 3,
|
||||
nOpCyclesXchgRM: 5,
|
||||
nOpCyclesXLAT: 5
|
||||
},
|
||||
/*
|
||||
* TODO: All 80386 cycle counts are based on 80286 counts until I have time to hand-generate an 80386-specific table;
|
||||
* the values below are used by selected 32-bit opcode handlers only.
|
||||
*/
|
||||
CYCLES_80386: {
|
||||
nEACyclesBase: 0,
|
||||
nEACyclesDisp: 0,
|
||||
nEACyclesBaseIndex: 0,
|
||||
nEACyclesBaseIndexExtra: 0,
|
||||
nEACyclesBaseDisp: 0,
|
||||
nEACyclesBaseIndexDisp: 1,
|
||||
nEACyclesBaseIndexDispExtra:1
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* BACKTRACK-related definitions (used only if BACKTRACK is defined)
|
||||
*/
|
||||
X86.BTINFO = {
|
||||
SP_LO: 0,
|
||||
SP_HI: 0
|
||||
};
|
||||
|
||||
/*
|
||||
* These PS flags are always stored directly in regPS for the 8086/8088, hence the
|
||||
* "direct" designation; other processors must adjust these bits accordingly. The final
|
||||
* adjusted value is stored in PS_DIRECT (ie, 80286 and up also include PS.IOPL.MASK and
|
||||
* PS.NT in PS_DIRECT).
|
||||
*/
|
||||
X86.PS_DIRECT_8086 = (X86.PS.TF | X86.PS.IF | X86.PS.DF);
|
||||
|
||||
/*
|
||||
* These are the default "always set" PS bits for the 8086/8088; other processors must
|
||||
* adjust these bits accordingly. The final adjusted value is stored in PS_SET.
|
||||
*/
|
||||
X86.PS_SET_8086 = (X86.PS.BIT1 | X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
|
||||
|
||||
/*
|
||||
* These PS arithmetic and logical flags may be "cached" across several result registers;
|
||||
* whether or not they're currently cached depends on the RESULT bits in resultType.
|
||||
*/
|
||||
X86.PS_CACHED = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF | X86.PS.OF);
|
||||
|
||||
/*
|
||||
* PS_SAHF is a subset of the arithmetic flags, and refers only to those flags that the
|
||||
* SAHF and LAHF "8080 legacy" opcodes affect.
|
||||
*/
|
||||
X86.PS_SAHF = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF);
|
||||
|
||||
/*
|
||||
* Before we zero opFlags, we first see if any of the following PREFIX bits were set. If any were set,
|
||||
* they are OR'ed into opPrefixes; otherwise, opPrefixes is zeroed as well. This gives prefix-conscious
|
||||
* instructions like LODS, MOVS, STOS, CMPS, etc, a way of determining which prefixes, if any, immediately
|
||||
* preceded them.
|
||||
*/
|
||||
X86.OPFLAG_PREFIXES = (X86.OPFLAG.SEG | X86.OPFLAG.LOCK | X86.OPFLAG.REPZ | X86.OPFLAG.REPNZ | X86.OPFLAG.DATASIZE | X86.OPFLAG.ADDRSIZE);
|
||||
|
||||
if (NODE) module.exports = X86;
|
||||
Loading…
Reference in a new issue