Updated 80386 A0 and B0 stepping information

(and some minor CPU tweaks for the 80386 as well)
This commit is contained in:
Jeff Parsons 2015-03-09 21:49:13 -07:00 • committed by jeffpar
commit 76932246ec
10 changed files with 1764 additions and 1470 deletions

View file

@ -22,27 +22,283 @@ If the self-test is not requested, the contents of EAX after RESET is undefined.
> DX holds a component identifier and revision number after RESET as Figure 10-1 illustrates. DH contains 3, > DX holds a component identifier and revision number after RESET as Figure 10-1 illustrates. DH contains 3,
which indicates an 80386 component. DL contains a unique identifier of the revision level. which indicates an 80386 component. DL contains a unique identifier of the revision level.
But what "revision levels" did Intel actually use? But what steppings did Intel produce, and what "revision level" was associated with each stepping?
Based on information below (see the ill-fated XBTS instruction), it seems there were A0-B0 steppings. I've read reports that the first stepping (A0) had serious problems, like an inability to return to real mode
However, all we can really infer from that is the existence of A0 and B0 steppings. It doesn't tell us (reminiscent of the 80286). Since it was never released commercially, and we know so little about it, let's move
whether there were any intervening (eg, A1, A2) steppings, or what revision levels were used on reset. on to the A1 stepping.
I've read reports that A steppings had serious problems, like an inability to return to real mode From "Advanced 80386 Programming Techniques" by James L. Turley (C) 1988:
(reminiscent of the 80286). By all accounts, no A-stepping 80386 CPUs were sold commercially, so we can
more or less ignore them.
As for the B0 stepping, the October 15, 1991 issue of PC Magazine reported: > ### Evolution of the 80386
> #### A1 Stepping
> This is the first revision after the initial (A0) introduction of the 80386 [in late 1985]. The A1
stepping became available around the first of the year in 1986.
> + *Hardware Peculiarity*: Unless pin F13 of the 80386 is connected to the +5V power supply, the 80386
never terminates a memory cycle, hanging the processor.
+ *Loading LDTR with a Null Selector*: If you load the local descriptor table register with a null
selector (0000 through 0003) without performing a memory read immediately afterward, the 80386 behaves
erratically. LDTR can be loaded either as the result of an LLDT instruction or as part of a task-switch
operation if the incoming TSS has a null selector in its LDT field.
+ *Loading Bad Stack Selectors*: The 80386 does not check the privilege level of the desired stack
segment selector during an LSS instruction. Normally, the RPL of the selector and the DPL of the segment
must exactly equal the DPL of the currently executing code segment.
+ *Misaligned Selectors*: If a 16-bit memory operand is loaded into a segment register, the 80386 hangs
if the selector is not word-aligned. This can happen with a MOV instruction and with the LDS, LES, LFS,
LGS, and LSS instructions.
+ *Testing Null Selectors*: The 80386 hangs if an LAR, LSL, VERR, or VERW instruction is used to test
a null selector.
+ *Popping Selectors*: When popping a segment selector from the stack, the 80386 performs all of the
privilege-related checks backward. That is, you are allowed to pop a selector to a segment with more
privilege, but not to one with less privilege.
+ *Indirect FAR JMP to Same Privilege Level*: An indirect JMP instruction is one in which the new segment
selector and offset are stored in memory. If the new code segment is at the same privilege level as the
current code segment, the 80386 does not read the selector portion of the JMP operand. The result is a
NEAR JMP to a new offset within the current code segment.
+ *Spurious Breakpoint Exceptions*: A MOV instruction into or out of the debug registers while hardware
breakpoints are enabled may cause a breakpoint fault to be reported. You should temporarily disable the
hardware breakpoints while reading or writing the debug registers and then execute a JMP instruction
to flush the prefetch queue before reenabling them.
+ *Successive Floating-Point Instructions*: If two floating-point instructions are executed close together,
the 80386 may force the coprocessor to start the second one too soon if the first one did not require any
memory operands.
+ *Bad Floating-Point Instructions*: The execution of certain undefined floating-point instructions causes
the 80386 to hang rather than reporting an invalid instruction fault.
+ *Misaligned Floating-Point Instructions*: If 80287 and/or 80387 instructions are not word-aligned, the
80386 passes the wrong instruction to the coprocessor, causing unpredictable behavior.
+ *Misaligned Descriptor Tables*: All segment descriptors should be dword-aligned, or the 80386 may not
read them correctly.
+ *Incorrect Interrupt Vector*: If a maskable interrupt occurs immediately after the 80386 has executed an
instruction with an 8-bit operand, the interrupt is always assigned a vector number of 0.
+ *Handling Exceptions with 80286 Tasks*: If an exception that pushes an error code is handled through a
task gate to an 80286 task, the 80386 generates a double fault (exception 8) as soon as the 80286 task
switch is completed.
+ *Page Fault During Task Switch*: If the new task uses different page tables than the old task and a page
fault occurs during the task-switch operation, the 80386 hangs instead of reporting the page fault.
+ *Returning from a Nested Task*: If you execute an IRET instruction when the NT (Nested Task) flag in
EFLAGS is set, the 80386 returns to your "parent" task. However, it will neglect to clear NT in the outgoing
task's TSS.
+ *Task-Switch Trap Bit*: When a task switch occurs and the incoming TSS has its task-switch bit set, the
80386 generates a debug fault (exception 1). However, it will neglect to set the BT flag in register DR6
before invoking the exception 1 handler.
+ *Invalid TSS Faults*: When an invalid TSS fault (exception 10) occurs as the result of a task-switch
operation, the 80386 pushes the wrong values for EIP and ESP on the error handler's stack.
+ *Wrong Paging Information During Task Switch*: When a task switch occurs and the new task uses a different
set of page tables than the old task (that is, CR3 in the TSS is different), the 80386 reads the new TSS
descriptor and updates the old TSS using the page tables of the new task.
+ *Masking NMI*: If an NMI is serviced through a task gate, the 80386 neglects to reenable NMI inputs after
the NMI-handling task terminates. The 80386 does not recognize NMI inputs while it is servicing an NMI.
+ *Incorrect Error Code*: If an exception that pushes an error code is handled through a task gate, the
80386 may push an error code of 0 instead of the correct error code.
+ *Not-Present LDT*: If a task switch occurs and the new task's TSS selector selects an LDT descriptor
that is marked no present, the 80386 reports a not-present fault (exception 11), instead of an invalid TSS
(exception 10).
+ *Self-test*: The self-test feature does not work on the A1 stepping of the 80386.
+ *Interlevel Transfers*: If you perform a control transfer to a higher privilege level and the procedure
at that level uses an expand-down stack segment for its stack, as opposed to an expand-up data segment,
the 80386 generates a spurious stack fault (exception 12).
+ *Debug Access Fault*: If an attempt is made to read or write the debug registers while GD is set in DR7,
the 80386 generates a debug fault (exception 1). However, the wrong value for EIP will be pushed onto the
exception handler's stack.
+ *Multiply and Divide Errors*: If the 80386 executes a MUL, IMUL, DIV, or IDIV instruction with a memory
operand and general protection fault (exception 13) occurs, the processor hangs rather than reporting the fault.
+ *Intersegment Transfers*: If the last 2 bytes of a direct FAR JMP or FAR CALL instruction are beyond the
end of the code segment, the 80386 hangs rather than reporting a general protection fault.
+ *Intersegment Transfers II*: If the last 2 bytes of a direct FAR JMP or FAR CALL instruction lie on the
other side of a page boundary, the 80386 hangs, regardless of whether the other page is present or not.
Remember, a page boundary occurs every 4kb.
+ *Bit-Test Instructions*: The bit-test instructions that perform read-modify-write cycles to memory (BTC,
BTR, and BTS) do not work properly unless your memory runs without wait states.
+ *Bit Scan Forward Instruction*: If a BSF instruction is executed with a memory operand, and a general
protection fault (exception 13) or a page fault (exception 14) occurs, the 80386 hangs rather than reporting
the fault.
+ *Accessing CR3, TR6, and TR7*: Reading or writing registers CR3, TR6, or TR7 produces incorrect results
if your memory requires wait states. This is particularly obscure, since these instructions do not reference
memory.
> #### B0 Stepping
> The B0 stepping became available around the middle of 1986. As is the case with earlier steppings, the
"B0" marking can sometimes be found on the outside of the device. If not, the code "S40336" or "S40337" may
appear. Starting with the B0 stepping, the 80386 would leave the component identifier, 3, in DH and the
revision identifier, also 3, in DL [Surprisingly, these are the same values that the B1 stepping reports
as well. -JP]
> + *Interrupts and Privilege Violations*: If a hardware interrupt occurs immediately before an IOPL-sensitive
instruction when CPL is greater than IOPL, the 80386 behaves erratically. Generally, it will produce spurious
stack faults (exception 12). Note that this occurs only if the IOPL-sensitive instruction was going to fail.
+ *Infinite Page Faults*: If a page fault (exception 14) occurs while the 80386 is attempting to invoke a
page fault handler, it generates another page fault rather than reporting a double fault (exception 8).
+ *Invalid TSS Fault*: If an invalid TSS fault (exception 10) is caused by an attempt to switch to a TSS that
is too small, and the exception is handled through a task gate, the 80386 shuts down.
+ *Invalid TSS Fault II*: If you execute an IRET instruction while the NT (Nested Task) flag is set in EFLAGS,
and the "parent" TSS is too small, the 80386 generates a double fault (exception 8).
+ *Invalid TSS Fault III*: If the previous error occurs and the double fault is handled through a trap gate,
the 80386 shuts down.
+ *Invalid TSS Fault IV*: If the gate descriptor for an invalid TSS fault (exception 10) is bad and an
invalid TSS fault occurs for any reason, the 80386 shuts down.
+ *Tracing a REP MOVS Instruction*: The 80386 does not correctly single-step (trace) repeated string move
instructions. Instead, it generates a debug trap after every *other* iteration of the repeated MOVS instruction.
+ *Breakpointing a REP MOVS Instruction*: If a data breakpoint is enabled and it is hit during a repeated
string move instruction, the 80386 reports it only after an even number of iterations. This gives you a
fifty-fifty chance of learning about your breakpoint one instruction late.
+ *16-Bit and 32-Bit Control Transfers*: Whenever control is transferred from 16-bit code to 32-bit code
through a task gate or through a gate that causes a change in privilege level, the 80386 discards the upper
half of the offset address in EIP. If the destination address was greater than 64Kb, this will cause a
program error.
+ *16-Bit and 32-Bit Control Transfers II*: When an IRET instruction that transfers control to a Virtual
8086 mode task is executed, the 80386 neglects to truncate the offset address on the stack to 16 bits.
+ *16-Bit and 32-Bit Control Transfers III*: If a 32-bit call, trap, or interrupt gate is used to transfer
control from a 16-bit code segment to a 32-bit code segment without changing privilege levels, the 80386
treats the gate as a 16-bit gate.
+ *Mixing Address Sizes*: If a LOOP, MOVS, LODS, STOS, CMPS, INS, or OUTS instruction is followed by an
instruction that uses a different address size, the 80386 may use the incorrect address size when updating
either the loop counter or the string index.
> #### B1 Stepping
> The B1 stepping became available in late 1986. It corrected many of the bugs in earlier versions, but
new ones were either introduced or discovered. The best known of these was the widely publicized multiply
failure discovered in mid-1987. The B1 stepping is identifiable either by the "B1" mark or by the code
"S40343," "S40344," or "S40362." As is the case with the B0 stepping, the B1 revision leaves a binary three
in DL after reset. [Surprisingly, these are the same values that the B0 stepping reports as well. -JP]
> + *IBTS and XBTS Instructions Removed*: The Insert Bit String (IBTS) and Extract Bit String (XBTS)
instructions were removed from the 80386's instruction set. It was determined that they took up too much
space on the microprocessor and that their functionality could be duplicated with the SHLD and SHRD
instructions. The opcodes 0F A6 and 0F A7 now produce invalid opcode faults.
+ *Multiplication Errors*: Certain 80386 microprocessors produce erroneous results when performing
multiplication. Not all B1 stepping 80386s suffer from this bug. It is aggravated by increases in the
processor's operating frequency, elevations in the ambient temperature, or decreases in the power supply
voltage. This failure is extremely pattern sensitive; certain patterns will produce errors readily, while
others never will. [See sample program below]
+ *Double Page Faults*: The bug that appeared in the B0 stepping regarding page faults that occurred
during page faults has been made a permanent feature of the 80386, with one minor change. If a third page
fault occurs while the processor is servicing the first two, the 80386 shuts down. [See Intel Errata #18 below]
+ *Disabling Page Translation*: The 80386 does not stop translating linear addresses to physical addresses
when paging is disabled. Any page-translation entries that are still in the cache will be used, regardless
of the setting of PG in CR0. To completely disable paging, flush the TLB by clearing CR3.
+ *Page Translation Affects I/O Addresses*: When paging is enabled, the MMU sometimes erroneously translates
I/O addresses above 0FFF as well as memory addresses. Coprocessor references (which appear in the I/O space)
are also affected. The I/O addresses are translated as though they were linear memory addresses, using the
memory translation tables cached in the TLB. If the "linear" I/O address is not in the cache, no translation
will take place; only cached entries produce this effect. [See Intel Errata #10 below]
+ *Page Fault Error Codes*: Under certain circumstances, the 80386 pushes an incorrect error code onto the
page fault handler's stack. [See Intel Errata #9 below]
+ *Four-Gigabyte Code Segments*: If you define a 4Gb code segment (limit = FFFFF, G = 1), the base address
of that segment must be dword-aligned, or the 80386 generates a general protection fault (exception 13)
when it fetches an instruction from the beginning of the segment. This feature is expected to become permanent.
+ *Wrong Loop Counter*: After a REP INS instruction finishes its last iteration, register ECX holds the value
FFFFFFFF instead of 0, if the next instruction after the REP INS references memory. [See Intel Errata #11 below]
+ *LSL Instruction and Stack Pointer*: If the LSL instruction is followed by an instruction that references
the stack, register ESP may become corrupted. [See Intel Errata #14 below]
+ *Not-Present LDT*: If a task switch occurs to a Virtual 8086 mode task and the incoming task's TSS holds
a selector to an LDT descriptor that is marked not present, the 80386 generates a not-present fault
(exception 11) rather than reporting an invalid TSS fault (exception 10). [See Intel Errata #16 below]
+ *Reading from CR3, TR6, or TR7*: If hardware breakpoints are enabled, reading from CR3, TR6, or TR7 may
cause spurious debug faults to be reported. It is recommended that you disable breakpoints and then execute
the MOV instruction followed by a JMP instruction before reenabling breakpoints.
+ *Privilege Checking a Null Selector*: If you perform an LAR, LSL, VERR, or VERw instruction using a null
selector (0000 through 0003), the 80386 actually checks the descriptor in slot 0 of the GDT instead of
always failing. [See Intel Errata #15 below]
+ *Privilege Checking Bad Selectors*: An LAR, LSL, VERR, or VERW instruction that checks an unreachable
selector causes the 80386 to hang unless there is a JMP, CALL, or memory-related instruction already in the
prefetch queue. An unreachable selector is one that either is beyond the limit of its descriptor table
or references a non-existent LDT. The processor will remain hung until it receives an interrupt.
+ *Faulting Floating-Point Instructions*: If the second byte of a floating-point instruction is located
in the first byte of a page that will cause a page fault (either because it is not present or because of an
impending privilege violation), the 80386 hangs. The processor will remain hung until it receives an interrupt.
[See Intel Errata #17 below]
> The following sample program has been calculated to produce the [multiplication] error. An 80386 that
fails one or more of these multiply instructions is obviously faulty. However, passing does not guarantee
a perfect part. To their credit, Intel agreed to test all 80386s for a limited time and report on their
success or failure. Since then, all 80386s have been tested before shipping. Those that fail have been marked
"For Sixteen-Bit Software Only." [I believe the exact marking was "16 BIT S/W ONLY" -JP] Those that passed
have been marked with a double sigma sign. All 80386s produced after the B1 stepping should be free of this
defect.
; Perform various 16-bit and 32-bit multiply operations...
K1 DD 41h ;memory-based constant 1
K2 DD 81h ;memory-based constant 2
MOV EAX,0042E8h ;load EAX with operand
MUL K1 ;EAX = EAX * 41H
CMP EAX,10FCE8h ;check answer
JNE fail ;failure if not equal
MOV EAX,085D00h
MUL K1
CMP EAX,021F9D00h
JNE fail
MOV EAX,042E80000h
MUL K1
CMP EAX,0FCE80000h
JNE fail
CMP EDX,010h
JNE fail
MOV EAX,0417A000h
MUL K2
CMP EAX,0FE7A000h
JNE fail
CMP EDX,0002h
JNE fail
MOV DX,0AB66h
MOV AX,09AE8h
MUL DX
CMP AX,0B070h
JNE fail
MOV DX,0FDF3h
MOV AX,09AE8h
MUL DX
CMP AX,05238h
JNE fail
MOV DX,0B554h
MOV AX,0E8EAh
MUL DX
CMP DX,0A4F9h
JNE fail
MOV DX,0B4C6h
MOV AX,0E8EAh
MUL DX
CMP AX,0ACFCh
JNE fail
CMP DX,0A478h
JNE fail
MOV DX,0B318h
MOV AX,0E8EAh
MUL DX
CMP DX,0A2F1h
JNE fail
MOV DX,0B43Bh
MOV AX,0E8EAh
MUL DX
CMP DX,0A3FAh
JNE fail
---
As for the B0 stepping, the October 15, 1991 issue of PC Magazine confirms what Turley noted above:
You can tell if you have a B0 or B1 Step level 386 by looking at the markings on the chip. You can tell if you have a B0 or B1 Step level 386 by looking at the markings on the chip.
If it has the ID number S40336 or S40337 stamped on it, then it's a Step B0; if it's marked If it has the ID number S40336 or S40337 stamped on it, then it's a Step B0; if it's marked
with S40343, S40344, or S40362, it's a Step B1. Some B0 and B1 chips were marked B0 or B1 with S40343, S40344, or S40362, it's a Step B1. Some B0 and B1 chips were marked B0 or B1
rather than with an ID number. rather than with an ID number.
Unfortunately, this doesn't tell us what revision number an 80386-B0 reported. Most of the information I have obtained about the 80386 begins with the B1 stepping. From a December
17, 1986 Intel document titled "**80386-B1 STEPPING INFORMATION**":
Most of the information I have about the 80386 begins with the B1 stepping. From a December 17, 1986
document titled "**80386-B1 STEPPING INFORMATION**":
80386-B1 component identifier readable in DH after reset: 03H 80386-B1 component identifier readable in DH after reset: 03H
80386-B1 revision identifier readable in DL after reset: 03H 80386-B1 revision identifier readable in DL after reset: 03H
@ -127,7 +383,7 @@ that time:
12. NMI Doesn't Always Bring Chip Out of Shutdown in Obscure Condition with Paging Enabled 12. NMI Doesn't Always Bring Chip Out of Shutdown in Obscure Condition with Paging Enabled
13. HOLD Input During Protected Mode Interlevel IRET when Paging is Enabled 13. HOLD Input During Protected Mode Interlevel IRET when Paging is Enabled
14. Protected Mode LSL Instruction Should not be Followed by PUSH/POP 14. Protected Mode LSL Instruction Should not be Followed by PUSH/POP
15. LSL/LAR/VERR/VERW. Instructions Malfunction with Null Selector 15. LSL/LAR/VERR/VERW Instructions Malfunction with Null Selector
16. "Not Present" LDT in VM86 Task Raises Wrong Exception 16. "Not Present" LDT in VM86 Task Raises Wrong Exception
17. Coprocessor Instructions Crossing Page/Segment Boundaries 17. Coprocessor Instructions Crossing Page/Segment Boundaries
18. Double Page Faults Do Not Raise Double Fault Exception 18. Double Page Faults Do Not Raise Double Fault Exception
@ -219,7 +475,8 @@ From the San Jose Mercury News, April 11, 1987:
anything else. "You have a complex chip here," said Daniel Klesken, an analyst for Montgomery anything else. "You have a complex chip here," said Daniel Klesken, an analyst for Montgomery
Securities in San Francisco. "One should not be surprised that (problems) happen occasionally." Securities in San Francisco. "One should not be surprised that (problems) happen occasionally."
The problem affected the B1 stepping; it's unknown whether other steppings were affected as well. The problem affected the B1 stepping; it's unknown whether other (earlier) steppings were affected
as well.
What follows is some additional information about early 80386 processors from various online sources. What follows is some additional information about early 80386 processors from various online sources.
@ -307,7 +564,37 @@ Never allocate valid memory at 0x80000xxx.
### Instructions ### Instructions
Regarding [Opcode XBTS](http://asm.inightmare.org/opcodelst/index.php?op=XBTS): Here's more information on the opcodes (IBTS and XBTS) that were removed from the B1 stepping.
[IBTS (0x0F 0xA7)](http://asm.inightmare.org/opcodelst/index.php?op=IBTS)
Opcode IBTS
CPU: 80386 step A0-B0 only
Type of Instruction: User
Instruction: IBTS base,bitoffset,len,sorc
Description:
Write bit string length bits from
[bits .. 0 ] (lowest bits) to bitfield,
defined by and bitsoffset from this base
to start of the field to write. String write from this start
field bit to higher memory addresses or register bits.
Flags Affected: None
CPU mode: RM,PM,VM
+++++++++++++++++++++++
Physical Form: IBTS r/m16,AX,CL,r16
IBTS r/m32,EAX,CL,r32
COP (Code of Operation) : 0FH A7H Postbyte
Clocks: IBTS
80386: 12/19
[XBTS (0x0F 0xA6)](http://asm.inightmare.org/opcodelst/index.php?op=XBTS):
Opcode XBTS Opcode XBTS
@ -343,3 +630,4 @@ Regarding [Opcode XBTS](http://asm.inightmare.org/opcodelst/index.php?op=XBTS):
*[@jeffpar](http://twitter.com/jeffpar)* *[@jeffpar](http://twitter.com/jeffpar)*
*February 23, 2015* *February 23, 2015*
*(Updated March 9, 2015 with information from "Advanced 80386 Programming Techniques")*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3044,7 +3044,7 @@ if (DEBUGGER) {
* @this {Debugger} * @this {Debugger}
* @param {number} bReg * @param {number} bReg
* @param {number} type * @param {number} type
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing) * @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addresses)
* @return {string} operand * @return {string} operand
*/ */
Debugger.prototype.getRegOperand = function(bReg, type, aAddr) Debugger.prototype.getRegOperand = function(bReg, type, aAddr)
@ -3077,7 +3077,7 @@ if (DEBUGGER) {
* *
* @this {Debugger} * @this {Debugger}
* @param {number} bMod * @param {number} bMod
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing) * @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addresses)
* @return {string} operand * @return {string} operand
*/ */
Debugger.prototype.getSIBOperand = function(bMod, aAddr) Debugger.prototype.getSIBOperand = function(bMod, aAddr)
@ -3104,7 +3104,7 @@ if (DEBUGGER) {
* @this {Debugger} * @this {Debugger}
* @param {number} bModRM * @param {number} bModRM
* @param {number} type * @param {number} type
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addressing) * @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addresses)
* @return {string} operand * @return {string} operand
*/ */
Debugger.prototype.getModRMOperand = function(bModRM, type, aAddr) Debugger.prototype.getModRMOperand = function(bModRM, type, aAddr)

View file

@ -50,11 +50,12 @@ var X86 = {
* we must add checks to those functions or throw a special JavaScript exception to bypass them. * we must add checks to those functions or throw a special JavaScript exception to bypass them.
* *
* This value is also used to indicate non-existent EA address calculations, which are usually * This value is also used to indicate non-existent EA address calculations, which are usually
* detected with "regEA < 0" and "regEAWrite < 0" tests, so be careful if you change this value. * detected with "regEA === ADDR_INVALID" and "regEAWrite === ADDR_INVALID" tests. In a 32-bit CPU,
* If/when we ever extend our physical address space beyond 24 bits (ie, when we break the 2Gb barrier), * -1 could actually be a valid address, so consider changing it to NaN or null; my concern is that,
* negative 32-bit values values will become valid addresses, so those tests will have to be revised. * by mixing non-numbers (specifically, values outside the range of 32-bit integers), performance
* may suffer.
*/ */
ADDR_INVALID: -4, ADDR_INVALID: -1,
/* /*
* Processor Status flag definitions (stored in regPS) * Processor Status flag definitions (stored in regPS)

View file

@ -3199,7 +3199,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
* instructions with multiple prefixes (eg, a REP and a segment override) would not be restarted * instructions with multiple prefixes (eg, a REP and a segment override) would not be restarted
* properly following a hardware interrupt. The recommended workarounds were to either turn off * properly following a hardware interrupt. The recommended workarounds were to either turn off
* interrupts or to follow the string instruction with a LOOPNZ back to the first prefix byte. * interrupts or to follow the string instruction with a LOOPNZ back to the first prefix byte.
* To emulate this flawed behavior, turn on BUGS_8086. * To emulate the flawed behavior, turn on BUGS_8086.
*/ */
this.opLIP = this.regLIP; this.opLIP = this.regLIP;
this.segData = this.segDS; this.segData = this.segDS;

View file

@ -51,7 +51,7 @@ X86.fnADCb = function ADCb(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultZeroCarry & 0xff; return this.resultZeroCarry & 0xff;
}; };
@ -69,7 +69,7 @@ X86.fnADCw = function ADCw(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultZeroCarry & 0xffff; return this.resultZeroCarry & 0xffff;
}; };
@ -85,7 +85,7 @@ X86.fnADDb = function ADDb(dst, src)
{ {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xff;
}; };
@ -101,7 +101,7 @@ X86.fnADDw = function ADDw(dst, src)
{ {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = dst + src) & 0xffff;
}; };
@ -114,7 +114,7 @@ X86.fnADDw = function ADDw(dst, src)
X86.fnANDb = function ANDb(dst, src) X86.fnANDb = function ANDb(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xff;
}; };
@ -127,7 +127,7 @@ X86.fnANDb = function ANDb(dst, src)
X86.fnANDw = function ANDw(dst, src) X86.fnANDw = function ANDw(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src) & 0xffff;
}; };
@ -140,7 +140,7 @@ X86.fnANDw = function ANDw(dst, src)
X86.fnANDd = function ANDd(dst, src) X86.fnANDd = function ANDd(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
var dw = this.resultParitySign = this.resultAuxOverflow = (dst & src); var dw = this.resultParitySign = this.resultAuxOverflow = (dst & src);
this.resultZeroCarry = ((dw >>> 16) | (dw & 0xffff)); this.resultZeroCarry = ((dw >>> 16) | (dw & 0xffff));
return dw; return dw;
@ -154,7 +154,7 @@ X86.fnANDd = function ANDd(dst, src)
*/ */
X86.fnARPL = function ARPL(dst, src) X86.fnARPL = function ARPL(dst, src)
{ {
this.nStepCycles -= (10 + (this.regEA < 0? 0 : 1)); this.nStepCycles -= (10 + (this.regEA === X86.ADDR_INVALID? 0 : 1));
if ((dst & X86.SEL.RPL) < (src & X86.SEL.RPL)) { if ((dst & X86.SEL.RPL) < (src & X86.SEL.RPL)) {
dst = (dst & ~X86.SEL.RPL) | (src & X86.SEL.RPL); dst = (dst & ~X86.SEL.RPL) | (src & X86.SEL.RPL);
this.setZF(); this.setZF();
@ -172,7 +172,7 @@ X86.fnARPL = function ARPL(dst, src)
*/ */
X86.fnBOUND = function BOUND(dst, src) X86.fnBOUND = function BOUND(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
/* /*
* Generate UD_FAULT (INT 0x06: Invalid Opcode) if src is not a memory operand. * Generate UD_FAULT (INT 0x06: Invalid Opcode) if src is not a memory operand.
*/ */
@ -229,7 +229,7 @@ X86.fnCALLw = function CALLw(dst, src)
{ {
this.pushWord(this.getIP()); this.pushWord(this.getIP());
this.setIP(dst); this.setIP(dst);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesCallWR : this.CYCLES.nOpCyclesCallWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesCallWR : this.CYCLES.nOpCyclesCallWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -242,7 +242,7 @@ X86.fnCALLw = function CALLw(dst, src)
*/ */
X86.fnCALLFdw = function CALLFdw(dst, src) X86.fnCALLFdw = function CALLFdw(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
return X86.fnGRPUndefined.call(this, dst, src); return X86.fnGRPUndefined.call(this, dst, src);
} }
X86.fnCALLF.call(this, dst, this.getShort(this.regEA + 2)); X86.fnCALLF.call(this, dst, this.getShort(this.regEA + 2));
@ -264,7 +264,7 @@ X86.fnCMPb = function CMPb(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.resultZeroCarry = this.resultParitySign = dst - src; this.resultZeroCarry = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -280,7 +280,7 @@ X86.fnCMPw = function CMPw(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.resultZeroCarry = this.resultParitySign = dst - src; this.resultZeroCarry = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -297,7 +297,7 @@ X86.fnDECb = function DECb(dst, src)
dst = (this.resultParitySign = dst - 1) & 0xff; dst = (this.resultParitySign = dst - 1) & 0xff;
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
}; };
@ -313,7 +313,7 @@ X86.fnDECw = function DECw(dst, src)
dst = (this.resultParitySign = dst - 1) & 0xffff; dst = (this.resultParitySign = dst - 1) & 0xffff;
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
}; };
@ -353,7 +353,7 @@ X86.fnDIVb = function DIVb(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('DIVB', src, dst, null, this.getPS(), this.regMD16); if (DEBUG && DEBUGGER) this.traceLog('DIVB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesDivBR : this.CYCLES.nOpCyclesDivBM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesDivBR : this.CYCLES.nOpCyclesDivBM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -400,7 +400,7 @@ X86.fnDIVw = function DIVw(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('DIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16)); if (DEBUG && DEBUGGER) this.traceLog('DIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesDivWR : this.CYCLES.nOpCyclesDivWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesDivWR : this.CYCLES.nOpCyclesDivWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -460,7 +460,7 @@ X86.fnIDIVb = function IDIVb(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('IDIVB', src, dst, null, this.getPS(), this.regMD16); if (DEBUG && DEBUGGER) this.traceLog('IDIVB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIDivBR : this.CYCLES.nOpCyclesIDivBM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIDivBR : this.CYCLES.nOpCyclesIDivBM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -512,7 +512,7 @@ X86.fnIDIVw = function IDIVw(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('IDIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16)); if (DEBUG && DEBUGGER) this.traceLog('IDIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIDivWR : this.CYCLES.nOpCyclesIDivWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIDivWR : this.CYCLES.nOpCyclesIDivWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -553,7 +553,7 @@ X86.fnIMUL8 = function IMUL8(dst, src)
* 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is * 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is
* not super-critical. TODO: Fix this someday. * not super-critical. TODO: Fix this someday.
*/ */
this.nStepCycles -= (this.regEA < 0? 21 : 24); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 21 : 24);
return result; return result;
}; };
@ -593,7 +593,7 @@ X86.fnIMUL16 = function IMUL16(dst, src)
* 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is * 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is
* not super-critical. TODO: Fix this someday. * not super-critical. TODO: Fix this someday.
*/ */
this.nStepCycles -= (this.regEA < 0? 21 : 24); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 21 : 24);
return result; return result;
}; };
@ -638,7 +638,7 @@ X86.fnIMULb = function IMULb(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('IMULB', src, dst, null, this.getPS(), this.regMD16); if (DEBUG && DEBUGGER) this.traceLog('IMULB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIMulBR : this.CYCLES.nOpCyclesIMulBM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIMulBR : this.CYCLES.nOpCyclesIMulBM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -685,7 +685,7 @@ X86.fnIMULw = function IMULw(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('IMULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16)); if (DEBUG && DEBUGGER) this.traceLog('IMULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIMulWR : this.CYCLES.nOpCyclesIMulWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIMulWR : this.CYCLES.nOpCyclesIMulWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -702,7 +702,7 @@ X86.fnINCb = function INCb(dst, src)
dst = (this.resultParitySign = dst + 1) & 0xff; dst = (this.resultParitySign = dst + 1) & 0xff;
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
}; };
@ -718,7 +718,7 @@ X86.fnINCw = function INCw(dst, src)
dst = (this.resultParitySign = dst + 1) & 0xffff; dst = (this.resultParitySign = dst + 1) & 0xffff;
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16); this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesIncR : this.CYCLES.nOpCyclesIncM);
return dst; return dst;
}; };
@ -796,7 +796,7 @@ X86.fnIRET = function IRET()
*/ */
X86.fnJMPFdw = function JMPFdw(dst, src) X86.fnJMPFdw = function JMPFdw(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
return X86.fnGRPUndefined.call(this, dst, src); return X86.fnGRPUndefined.call(this, dst, src);
} }
this.setCSIP(dst, this.getShort(this.regEA + 2)); this.setCSIP(dst, this.getShort(this.regEA + 2));
@ -815,7 +815,7 @@ X86.fnJMPFdw = function JMPFdw(dst, src)
X86.fnJMPw = function JMPw(dst, src) X86.fnJMPw = function JMPw(dst, src)
{ {
this.setIP(dst); this.setIP(dst);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesJmpWR : this.CYCLES.nOpCyclesJmpWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesJmpWR : this.CYCLES.nOpCyclesJmpWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -828,7 +828,7 @@ X86.fnJMPw = function JMPw(dst, src)
*/ */
X86.fnLAR = function LAR(dst, src) X86.fnLAR = function LAR(dst, src)
{ {
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
/* /*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the * Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment. * descriptor table or the descriptor is not for a segment.
@ -870,7 +870,7 @@ X86.fnLCR0 = function LCR0(l)
*/ */
X86.fnLDS = function LDS(dst, src) X86.fnLDS = function LDS(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opUndefined.call(this); X86.opUndefined.call(this);
return dst; return dst;
} }
@ -887,7 +887,7 @@ X86.fnLDS = function LDS(dst, src)
*/ */
X86.fnLEA = function LEA(dst, src) X86.fnLEA = function LEA(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
/* /*
* TODO: After reading http://www.os2museum.com/wp/undocumented-8086-opcodes/, it seems that this * TODO: After reading http://www.os2museum.com/wp/undocumented-8086-opcodes/, it seems that this
* form of LEA (eg, "LEA AX,DX") simply returns the last calculated EA. Since we always reset regEA * form of LEA (eg, "LEA AX,DX") simply returns the last calculated EA. Since we always reset regEA
@ -920,7 +920,7 @@ X86.fnLEA = function LEA(dst, src)
*/ */
X86.fnLGDT = function LGDT(dst, src) X86.fnLGDT = function LGDT(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opInvalid.call(this); X86.opInvalid.call(this);
} else { } else {
this.addrGDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16); this.addrGDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
@ -939,7 +939,7 @@ X86.fnLGDT = function LGDT(dst, src)
*/ */
X86.fnLES = function LES(dst, src) X86.fnLES = function LES(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opUndefined.call(this); X86.opUndefined.call(this);
return dst; return dst;
} }
@ -964,7 +964,7 @@ X86.fnLES = function LES(dst, src)
*/ */
X86.fnLIDT = function LIDT(dst, src) X86.fnLIDT = function LIDT(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opInvalid.call(this); X86.opInvalid.call(this);
} else { } else {
this.addrIDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16); this.addrIDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
@ -988,7 +988,7 @@ X86.fnLIDT = function LIDT(dst, src)
X86.fnLLDT = function LLDT(dst, src) { X86.fnLLDT = function LLDT(dst, src) {
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
this.segLDT.load(dst); this.segLDT.load(dst);
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
return dst; return dst;
}; };
@ -1005,7 +1005,7 @@ X86.fnLLDT = function LLDT(dst, src) {
X86.fnLMSW = function LMSW(dst, src) X86.fnLMSW = function LMSW(dst, src)
{ {
this.setMSW(dst); this.setMSW(dst);
this.nStepCycles -= (this.regEA < 0? 3 : 6); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1021,7 +1021,7 @@ X86.fnLSL = function LSL(dst, src)
/* /*
* TODO: Is this an invalid operation if regEAWrite is set? dst is required to be a register. * TODO: Is this an invalid operation if regEAWrite is set? dst is required to be a register.
*/ */
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
/* /*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the * Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment. * descriptor table or the descriptor is not for a segment.
@ -1057,7 +1057,7 @@ X86.fnLTR = function LTR(dst, src)
this.setShort(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.LDT); this.setShort(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.LDT);
this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY; this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
} }
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
return dst; return dst;
}; };
@ -1069,7 +1069,7 @@ X86.fnLTR = function LTR(dst, src)
*/ */
X86.fnMOV = function MOV(dst, src) X86.fnMOV = function MOV(dst, src)
{ {
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesMovRR : this.CYCLES.nOpCyclesMovRM) : this.CYCLES.nOpCyclesMovMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesMovRR : this.CYCLES.nOpCyclesMovRM) : this.CYCLES.nOpCyclesMovMR);
return src; return src;
}; };
@ -1081,7 +1081,7 @@ X86.fnMOV = function MOV(dst, src)
*/ */
X86.fnMOVImm = function MOVImm(dst, src) X86.fnMOVImm = function MOVImm(dst, src)
{ {
this.nStepCycles -= (this.regEAWrite < 0? this.CYCLES.nOpCyclesMovRI : this.CYCLES.nOpCyclesMovMI); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? this.CYCLES.nOpCyclesMovRI : this.CYCLES.nOpCyclesMovMI);
return src; return src;
}; };
@ -1123,7 +1123,7 @@ X86.fnMULb = function MULb(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('MULB', src, dst, null, this.getPS(), this.regMD16); if (DEBUG && DEBUGGER) this.traceLog('MULB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesMulBR : this.CYCLES.nOpCyclesMulBM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesMulBR : this.CYCLES.nOpCyclesMulBM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1156,7 +1156,7 @@ X86.fnMULw = function MULw(dst, src)
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src. * dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/ */
if (DEBUG && DEBUGGER) this.traceLog('MULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16)); if (DEBUG && DEBUGGER) this.traceLog('MULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesMulWR : this.CYCLES.nOpCyclesMulWM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesMulWR : this.CYCLES.nOpCyclesMulWM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1172,7 +1172,7 @@ X86.fnNEGb = function NEGb(dst, src)
src = 0; src = 0;
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xff; return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xff;
}; };
@ -1187,7 +1187,7 @@ X86.fnNEGw = function NEGw(dst, src)
src = 0; src = 0;
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = src - dst) & 0xffff;
}; };
@ -1199,7 +1199,7 @@ X86.fnNEGw = function NEGw(dst, src)
*/ */
X86.fnNOTb = function NOTb(dst, src) X86.fnNOTb = function NOTb(dst, src)
{ {
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return dst ^ 0xff; return dst ^ 0xff;
}; };
@ -1211,7 +1211,7 @@ X86.fnNOTb = function NOTb(dst, src)
*/ */
X86.fnNOTw = function NOTw(dst, src) X86.fnNOTw = function NOTw(dst, src)
{ {
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesNegR : this.CYCLES.nOpCyclesNegM);
return dst ^ 0xffff; return dst ^ 0xffff;
}; };
@ -1224,7 +1224,7 @@ X86.fnNOTw = function NOTw(dst, src)
X86.fnORb = function ORb(dst, src) X86.fnORb = function ORb(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xff;
}; };
@ -1237,7 +1237,7 @@ X86.fnORb = function ORb(dst, src)
X86.fnORw = function ORw(dst, src) X86.fnORw = function ORw(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst | src) & 0xffff;
}; };
@ -1249,7 +1249,7 @@ X86.fnORw = function ORw(dst, src)
*/ */
X86.fnPOPw = function POPw(dst, src) X86.fnPOPw = function POPw(dst, src)
{ {
this.nStepCycles -= (this.regEAWrite < 0? this.CYCLES.nOpCyclesPopReg : this.CYCLES.nOpCyclesPopMem); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? this.CYCLES.nOpCyclesPopReg : this.CYCLES.nOpCyclesPopMem);
return src; return src;
}; };
@ -1275,7 +1275,7 @@ X86.fnPUSHw = function PUSHw(dst, src)
if (this.model < X86.MODEL_80286) w = dst; if (this.model < X86.MODEL_80286) w = dst;
} }
this.pushWord(w); this.pushWord(w);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesPushReg : this.CYCLES.nOpCyclesPushMem); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesPushReg : this.CYCLES.nOpCyclesPushMem);
/* /*
* The PUSH is the only write that needs to occur; dst was the source operand and does not need to be rewritten. * The PUSH is the only write that needs to occur; dst was the source operand and does not need to be rewritten.
*/ */
@ -1571,7 +1571,7 @@ X86.fnSBBb = function SBBb(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultZeroCarry & 0xff; return this.resultZeroCarry & 0xff;
}; };
@ -1589,7 +1589,7 @@ X86.fnSBBw = function SBBw(dst, src)
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0); this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return this.resultZeroCarry & 0xffff; return this.resultZeroCarry & 0xffff;
}; };
@ -1605,7 +1605,7 @@ X86.fnSBBw = function SBBw(dst, src)
*/ */
X86.fnSGDT = function SGDT(dst, src) X86.fnSGDT = function SGDT(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opInvalid.call(this); X86.opInvalid.call(this);
} else { } else {
/* /*
@ -1779,7 +1779,7 @@ X86.fnSHRw = function SHRw(dst, src)
*/ */
X86.fnSIDT = function SIDT(dst, src) X86.fnSIDT = function SIDT(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
X86.opInvalid.call(this); X86.opInvalid.call(this);
} else { } else {
/* /*
@ -1812,7 +1812,7 @@ X86.fnSIDT = function SIDT(dst, src)
*/ */
X86.fnSLDT = function SLDT(dst, src) X86.fnSLDT = function SLDT(dst, src)
{ {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1)); this.nStepCycles -= (2 + (this.regEA === X86.ADDR_INVALID? 0 : 1));
return this.segLDT.sel; return this.segLDT.sel;
}; };
@ -1828,7 +1828,7 @@ X86.fnSLDT = function SLDT(dst, src)
*/ */
X86.fnSMSW = function SMSW(dst, src) X86.fnSMSW = function SMSW(dst, src)
{ {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1)); this.nStepCycles -= (2 + (this.regEA === X86.ADDR_INVALID? 0 : 1));
return this.regCR0; return this.regCR0;
}; };
@ -1844,7 +1844,7 @@ X86.fnSMSW = function SMSW(dst, src)
*/ */
X86.fnSTR = function STR(dst, src) X86.fnSTR = function STR(dst, src)
{ {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1)); this.nStepCycles -= (2 + (this.regEA === X86.ADDR_INVALID? 0 : 1));
return this.segTSS.sel; return this.segTSS.sel;
}; };
@ -1858,7 +1858,7 @@ X86.fnSUBb = function SUBb(dst, src)
{ {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xff;
}; };
@ -1872,7 +1872,7 @@ X86.fnSUBw = function SUBw(dst, src)
{ {
this.resultAuxOverflow = dst ^ src; this.resultAuxOverflow = dst ^ src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = dst - src) & 0xffff;
}; };
@ -1887,7 +1887,7 @@ X86.fnTEST8 = function TEST8(dst, src)
src = this.getIPByte(); src = this.getIPByte();
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1903,7 +1903,7 @@ X86.fnTEST16 = function TEST16(dst, src)
src = this.getIPWord(); src = this.getIPWord();
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1918,7 +1918,7 @@ X86.fnTESTb = function TESTb(dst, src)
{ {
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1933,7 +1933,7 @@ X86.fnTESTw = function TESTw(dst, src)
{ {
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src; this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE; this.opFlags |= X86.OPFLAG.NOWRITE;
return dst; return dst;
}; };
@ -1955,7 +1955,7 @@ X86.fnVERR = function VERR(dst, src)
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the * Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment. * descriptor table or the descriptor is not for a segment.
*/ */
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
if (this.segVER.load(dst, true) != X86.ADDR_INVALID) { if (this.segVER.load(dst, true) != X86.ADDR_INVALID) {
/* /*
* Verify that this is a readable segment; that is, of these four combinations (code+readable, * Verify that this is a readable segment; that is, of these four combinations (code+readable,
@ -1997,7 +1997,7 @@ X86.fnVERW = function VERW(dst, src)
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the * Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment. * descriptor table or the descriptor is not for a segment.
*/ */
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2)); this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
if (this.segVER.load(dst, true) != X86.ADDR_INVALID) { if (this.segVER.load(dst, true) != X86.ADDR_INVALID) {
/* /*
* Verify that this is a writable data segment * Verify that this is a writable data segment
@ -2043,7 +2043,7 @@ X86.fnVERW = function VERW(dst, src)
*/ */
X86.fnXCHGrb = function XCHGRb(dst, src) X86.fnXCHGrb = function XCHGRb(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
/* /*
* Decode which register was src * Decode which register was src
*/ */
@ -2107,7 +2107,7 @@ X86.fnXCHGrb = function XCHGRb(dst, src)
*/ */
X86.fnXCHGrw = function XCHGRw(dst, src) X86.fnXCHGrw = function XCHGRw(dst, src)
{ {
if (this.regEA < 0) { if (this.regEA === X86.ADDR_INVALID) {
/* /*
* Decode which register was src * Decode which register was src
*/ */
@ -2162,7 +2162,7 @@ X86.fnXCHGrw = function XCHGRw(dst, src)
X86.fnXORb = function XORb(dst, src) X86.fnXORb = function XORb(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_BYTE; this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xff;
}; };
@ -2175,7 +2175,7 @@ X86.fnXORb = function XORb(dst, src)
X86.fnXORw = function XORw(dst, src) X86.fnXORw = function XORw(dst, src)
{ {
this.resultSize = X86.RESULT.SIZE_WORD; this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesArithRM) : this.CYCLES.nOpCyclesArithMR);
return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xffff; return (this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst ^ src) & 0xffff;
}; };
@ -2210,7 +2210,7 @@ X86.fnRotateFlags = function(result, size)
* @return {number} * @return {number}
*/ */
X86.fnGRPCount1 = function() { X86.fnGRPCount1 = function() {
this.nStepCycles -= (this.regEA < 0? 2 : this.CYCLES.nOpCyclesShift1M); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 2 : this.CYCLES.nOpCyclesShift1M);
return 1; return 1;
}; };
@ -2220,7 +2220,7 @@ X86.fnGRPCount1 = function() {
*/ */
X86.fnGRPCountCL = function() { X86.fnGRPCountCL = function() {
var count = this.regECX & this.nShiftCountMask; var count = this.regECX & this.nShiftCountMask;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS);
return count; return count;
}; };
@ -2230,7 +2230,7 @@ X86.fnGRPCountCL = function() {
*/ */
X86.fnGRPCountImm = function() { X86.fnGRPCountImm = function() {
var count = this.getIPByte(); var count = this.getIPByte();
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS); this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS);
return count; return count;
}; };

View file

@ -47,10 +47,13 @@ X86.opADDmb = function ADDmb()
{ {
var b = this.getIPByte(); var b = this.getIPByte();
/* /*
* Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started executing * Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started
* in the weeds, so we'll stop the CPU if we're in DEBUG mode. * executing in the weeds, so we'll print a warning if Messages.CPU is enabled (at which
* point you can also choose to halt if Messages.HALT is enabled).
*/ */
if (DEBUG && DEBUGGER && !b) this.stopCPU(); if (DEBUG && !b) {
this.printMessage("suspicious opcode: 0x00 0x00");
}
this.aOpModMemByte[b].call(this, X86.fnADDb); this.aOpModMemByte[b].call(this, X86.fnADDb);
}; };
@ -2133,7 +2136,7 @@ X86.opJNLE = function JNLE()
X86.opGrp1b = function GRP1b() X86.opGrp1b = function GRP1b()
{ {
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp1b, this.getIPByte); this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp1b, this.getIPByte);
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
}; };
/** /**
@ -2144,7 +2147,7 @@ X86.opGrp1b = function GRP1b()
X86.opGrp1w = function GRP1w() X86.opGrp1w = function GRP1w()
{ {
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPWord); this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPWord);
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
}; };
/** /**
@ -2155,7 +2158,7 @@ X86.opGrp1w = function GRP1w()
X86.opGrp1sw = function GRP1sw() X86.opGrp1sw = function GRP1sw()
{ {
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPDisp); this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPDisp);
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID); this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
}; };
/** /**
@ -2627,7 +2630,7 @@ X86.opCALLF = function CALLF()
*/ */
X86.opWAIT = function WAIT() X86.opWAIT = function WAIT()
{ {
this.printMessage("WAIT not implemented", Messages.CPU); this.printMessage("WAIT not implemented");
this.nStepCycles--; this.nStepCycles--;
}; };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long