Updated 80386 A0 and B0 stepping information
(and some minor CPU tweaks for the 80386 as well)
This commit is contained in:
parent
568c4e031e
commit
76932246ec
10 changed files with 1764 additions and 1470 deletions
|
|
@ -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,
|
||||
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.
|
||||
However, all we can really infer from that is the existence of A0 and B0 steppings. It doesn't tell us
|
||||
whether there were any intervening (eg, A1, A2) steppings, or what revision levels were used on reset.
|
||||
I've read reports that the first stepping (A0) had serious problems, like an inability to return to real mode
|
||||
(reminiscent of the 80286). Since it was never released commercially, and we know so little about it, let's move
|
||||
on to the A1 stepping.
|
||||
|
||||
I've read reports that A steppings had serious problems, like an inability to return to real mode
|
||||
(reminiscent of the 80286). By all accounts, no A-stepping 80386 CPUs were sold commercially, so we can
|
||||
more or less ignore them.
|
||||
From "Advanced 80386 Programming Techniques" by James L. Turley (C) 1988:
|
||||
|
||||
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.
|
||||
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
|
||||
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 about the 80386 begins with the B1 stepping. From a December 17, 1986
|
||||
document titled "**80386-B1 STEPPING INFORMATION**":
|
||||
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**":
|
||||
|
||||
80386-B1 component identifier readable in DH 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
|
||||
13. HOLD Input During Protected Mode Interlevel IRET when Paging is Enabled
|
||||
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
|
||||
17. Coprocessor Instructions Crossing Page/Segment Boundaries
|
||||
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
|
||||
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.
|
||||
|
||||
|
|
@ -307,7 +564,37 @@ Never allocate valid memory at 0x80000xxx.
|
|||
|
||||
### 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
|
||||
|
||||
|
|
@ -343,3 +630,4 @@ Regarding [Opcode XBTS](http://asm.inightmare.org/opcodelst/index.php?op=XBTS):
|
|||
|
||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||
*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
|
|
@ -3044,7 +3044,7 @@ if (DEBUGGER) {
|
|||
* @this {Debugger}
|
||||
* @param {number} bReg
|
||||
* @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
|
||||
*/
|
||||
Debugger.prototype.getRegOperand = function(bReg, type, aAddr)
|
||||
|
|
@ -3077,7 +3077,7 @@ if (DEBUGGER) {
|
|||
*
|
||||
* @this {Debugger}
|
||||
* @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
|
||||
*/
|
||||
Debugger.prototype.getSIBOperand = function(bMod, aAddr)
|
||||
|
|
@ -3104,7 +3104,7 @@ if (DEBUGGER) {
|
|||
* @this {Debugger}
|
||||
* @param {number} bModRM
|
||||
* @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
|
||||
*/
|
||||
Debugger.prototype.getModRMOperand = function(bModRM, type, aAddr)
|
||||
|
|
|
|||
|
|
@ -50,11 +50,12 @@ var X86 = {
|
|||
* 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
|
||||
* detected with "regEA < 0" and "regEAWrite < 0" tests, so be careful if you change this value.
|
||||
* If/when we ever extend our physical address space beyond 24 bits (ie, when we break the 2Gb barrier),
|
||||
* negative 32-bit values values will become valid addresses, so those tests will have to be revised.
|
||||
* detected with "regEA === ADDR_INVALID" and "regEAWrite === ADDR_INVALID" tests. In a 32-bit CPU,
|
||||
* -1 could actually be a valid address, so consider changing it to NaN or null; my concern is that,
|
||||
* 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)
|
||||
|
|
|
|||
|
|
@ -3199,7 +3199,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
|
|||
* 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
|
||||
* 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.segData = this.segDS;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ X86.fnADCb = function ADCb(dst, src)
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ X86.fnADCw = function ADCw(dst, src)
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultZeroCarry = this.resultParitySign = dst + src + ((this.resultZeroCarry & this.resultSize)? 1 : 0);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ X86.fnADDb = function ADDb(dst, src)
|
|||
{
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ X86.fnADDw = function ADDw(dst, src)
|
|||
{
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ X86.fnADDw = function ADDw(dst, src)
|
|||
X86.fnANDb = function ANDb(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ X86.fnANDb = function ANDb(dst, src)
|
|||
X86.fnANDw = function ANDw(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ X86.fnANDw = function ANDw(dst, src)
|
|||
X86.fnANDd = function ANDd(dst, src)
|
||||
{
|
||||
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);
|
||||
this.resultZeroCarry = ((dw >>> 16) | (dw & 0xffff));
|
||||
return dw;
|
||||
|
|
@ -154,7 +154,7 @@ X86.fnANDd = function ANDd(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)) {
|
||||
dst = (dst & ~X86.SEL.RPL) | (src & X86.SEL.RPL);
|
||||
this.setZF();
|
||||
|
|
@ -172,7 +172,7 @@ X86.fnARPL = function ARPL(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.
|
||||
*/
|
||||
|
|
@ -229,7 +229,7 @@ X86.fnCALLw = function CALLw(dst, src)
|
|||
{
|
||||
this.pushWord(this.getIP());
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -242,7 +242,7 @@ X86.fnCALLw = function CALLw(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);
|
||||
}
|
||||
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.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -280,7 +280,7 @@ X86.fnCMPw = function CMPw(dst, src)
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -297,7 +297,7 @@ X86.fnDECb = function DECb(dst, src)
|
|||
dst = (this.resultParitySign = dst - 1) & 0xff;
|
||||
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ X86.fnDECw = function DECw(dst, src)
|
|||
dst = (this.resultParitySign = dst - 1) & 0xffff;
|
||||
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
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
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -702,7 +702,7 @@ X86.fnINCb = function INCb(dst, src)
|
|||
dst = (this.resultParitySign = dst + 1) & 0xff;
|
||||
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 8);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -718,7 +718,7 @@ X86.fnINCw = function INCw(dst, src)
|
|||
dst = (this.resultParitySign = dst + 1) & 0xffff;
|
||||
this.resultZeroCarry = dst | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -796,7 +796,7 @@ X86.fnIRET = function IRET()
|
|||
*/
|
||||
X86.fnJMPFdw = function JMPFdw(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
return X86.fnGRPUndefined.call(this, dst, src);
|
||||
}
|
||||
this.setCSIP(dst, this.getShort(this.regEA + 2));
|
||||
|
|
@ -815,7 +815,7 @@ X86.fnJMPFdw = function JMPFdw(dst, src)
|
|||
X86.fnJMPw = function JMPw(dst, src)
|
||||
{
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -828,7 +828,7 @@ X86.fnJMPw = function JMPw(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
|
||||
* 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)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opUndefined.call(this);
|
||||
return dst;
|
||||
}
|
||||
|
|
@ -887,7 +887,7 @@ X86.fnLDS = function LDS(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
|
||||
* 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)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opUndefined.call(this);
|
||||
return dst;
|
||||
}
|
||||
|
|
@ -964,7 +964,7 @@ X86.fnLES = function LES(dst, src)
|
|||
*/
|
||||
X86.fnLIDT = function LIDT(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
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) {
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
this.segLDT.load(dst);
|
||||
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2));
|
||||
this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
|
||||
return dst;
|
||||
};
|
||||
|
||||
|
|
@ -1005,7 +1005,7 @@ X86.fnLLDT = function LLDT(dst, src) {
|
|||
X86.fnLMSW = function LMSW(dst, src)
|
||||
{
|
||||
this.setMSW(dst);
|
||||
this.nStepCycles -= (this.regEA < 0? 3 : 6);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 3 : 6);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
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.
|
||||
*/
|
||||
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
|
||||
* 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.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;
|
||||
};
|
||||
|
||||
|
|
@ -1069,7 +1069,7 @@ X86.fnLTR = function LTR(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;
|
||||
};
|
||||
|
||||
|
|
@ -1081,7 +1081,7 @@ X86.fnMOV = function MOV(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;
|
||||
};
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1172,7 +1172,7 @@ X86.fnNEGb = function NEGb(dst, src)
|
|||
src = 0;
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1187,7 +1187,7 @@ X86.fnNEGw = function NEGw(dst, src)
|
|||
src = 0;
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1199,7 +1199,7 @@ X86.fnNEGw = function NEGw(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;
|
||||
};
|
||||
|
||||
|
|
@ -1211,7 +1211,7 @@ X86.fnNOTb = function NOTb(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;
|
||||
};
|
||||
|
||||
|
|
@ -1224,7 +1224,7 @@ X86.fnNOTw = function NOTw(dst, src)
|
|||
X86.fnORb = function ORb(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1237,7 +1237,7 @@ X86.fnORb = function ORb(dst, src)
|
|||
X86.fnORw = function ORw(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1249,7 +1249,7 @@ X86.fnORw = function ORw(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;
|
||||
};
|
||||
|
||||
|
|
@ -1275,7 +1275,7 @@ X86.fnPUSHw = function PUSHw(dst, src)
|
|||
if (this.model < X86.MODEL_80286) w = dst;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
|
@ -1571,7 +1571,7 @@ X86.fnSBBb = function SBBb(dst, src)
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1589,7 +1589,7 @@ X86.fnSBBw = function SBBw(dst, src)
|
|||
this.resultAuxOverflow = dst ^ src;
|
||||
this.resultZeroCarry = this.resultParitySign = dst - src - ((this.resultZeroCarry & this.resultSize)? 1 : 0);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1605,7 +1605,7 @@ X86.fnSBBw = function SBBw(dst, src)
|
|||
*/
|
||||
X86.fnSGDT = function SGDT(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -1779,7 +1779,7 @@ X86.fnSHRw = function SHRw(dst, src)
|
|||
*/
|
||||
X86.fnSIDT = function SIDT(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -1812,7 +1812,7 @@ X86.fnSIDT = function SIDT(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;
|
||||
};
|
||||
|
||||
|
|
@ -1828,7 +1828,7 @@ X86.fnSLDT = function SLDT(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;
|
||||
};
|
||||
|
||||
|
|
@ -1844,7 +1844,7 @@ X86.fnSMSW = function SMSW(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;
|
||||
};
|
||||
|
||||
|
|
@ -1858,7 +1858,7 @@ X86.fnSUBb = function SUBb(dst, src)
|
|||
{
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1872,7 +1872,7 @@ X86.fnSUBw = function SUBw(dst, src)
|
|||
{
|
||||
this.resultAuxOverflow = dst ^ src;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1887,7 +1887,7 @@ X86.fnTEST8 = function TEST8(dst, src)
|
|||
src = this.getIPByte();
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1903,7 +1903,7 @@ X86.fnTEST16 = function TEST16(dst, src)
|
|||
src = this.getIPWord();
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1918,7 +1918,7 @@ X86.fnTESTb = function TESTb(dst, src)
|
|||
{
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
|
||||
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;
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1933,7 +1933,7 @@ X86.fnTESTw = function TESTw(dst, src)
|
|||
{
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
|
||||
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;
|
||||
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
|
||||
* 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) {
|
||||
/*
|
||||
* 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
|
||||
* 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) {
|
||||
/*
|
||||
* Verify that this is a writable data segment
|
||||
|
|
@ -2043,7 +2043,7 @@ X86.fnVERW = function VERW(dst, src)
|
|||
*/
|
||||
X86.fnXCHGrb = function XCHGRb(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
/*
|
||||
* Decode which register was src
|
||||
*/
|
||||
|
|
@ -2107,7 +2107,7 @@ X86.fnXCHGrb = function XCHGRb(dst, src)
|
|||
*/
|
||||
X86.fnXCHGrw = function XCHGRw(dst, src)
|
||||
{
|
||||
if (this.regEA < 0) {
|
||||
if (this.regEA === X86.ADDR_INVALID) {
|
||||
/*
|
||||
* Decode which register was src
|
||||
*/
|
||||
|
|
@ -2162,7 +2162,7 @@ X86.fnXCHGrw = function XCHGRw(dst, src)
|
|||
X86.fnXORb = function XORb(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -2175,7 +2175,7 @@ X86.fnXORb = function XORb(dst, src)
|
|||
X86.fnXORw = function XORw(dst, src)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -2210,7 +2210,7 @@ X86.fnRotateFlags = function(result, size)
|
|||
* @return {number}
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -2220,7 +2220,7 @@ X86.fnGRPCount1 = function() {
|
|||
*/
|
||||
X86.fnGRPCountCL = function() {
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -2230,7 +2230,7 @@ X86.fnGRPCountCL = function() {
|
|||
*/
|
||||
X86.fnGRPCountImm = function() {
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -47,10 +47,13 @@ X86.opADDmb = function ADDmb()
|
|||
{
|
||||
var b = this.getIPByte();
|
||||
/*
|
||||
* Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started executing
|
||||
* in the weeds, so we'll stop the CPU if we're in DEBUG mode.
|
||||
* Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started
|
||||
* 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);
|
||||
};
|
||||
|
||||
|
|
@ -2133,7 +2136,7 @@ X86.opJNLE = function JNLE()
|
|||
X86.opGrp1b = function GRP1b()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
this.printMessage("WAIT not implemented", Messages.CPU);
|
||||
this.printMessage("WAIT not implemented");
|
||||
this.nStepCycles--;
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue