Assorted 80386 tweaks

This commit is contained in:
Jeff Parsons 2015-03-24 11:20:47 -07:00 committed by jeffpar
commit f5c0930f83
8 changed files with 255 additions and 232 deletions

View file

@ -5,11 +5,9 @@ Assembling a detailed and accurate history of the 80386, including a complete li
problems were fixed by a later stepping, seems virtually impossible at this late date.
I won't make the attempt here, either. Using information from various sources, I'll start with an overview
of the steppings (revision levels), including how each stepping was externally marked and internally identified,
along with lists of associated errata, then move on to more detailed errata information (from Intel's own documents),
and end with a summary of undocumented 80386 instructions.
Until further notice, this document is a work-in-progress.
of the steppings, including how each stepping was externally marked and internally identified, along with lists
of associated errata, then move on to more detailed errata information (from Intel's own documents), and end
with a summary of undocumented 80386 instructions.
### Steppings
@ -378,7 +376,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
fields are correctly stored. Note that coprocessor error-handling routines are the only routines possibly
affected. Also note that the problem does not occur in PROTECTED mode programs (since no opcode is saved
by FSAVE or FSTENV in that case).
 
**Workaround**: In REAL mode or in VIRTUAL 8086 mode, the instruction linear address field can be used to
read the opcode from memory. Note that the two bytes fetched need to be swapped to yield the image that
FSAVE and FSTENV normally stores.
@ -386,7 +383,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
**Problem**: If either of the last two bytes of an FSAVE or an FSTENV operand are for any reason not writeable,
or either of the last two bytes of an FRESTOR or FLDENV are for any reason not readable, the instruction
is not restartable.
 
**Workaround**: This does not not affect typical systems with reasonably-assigned page access rights.
In an obscure situation where this problem arises, a workaround is to avoid having the operand of these
instructions span a page boundary. This can be accomplished by aligning these operands on any 128-byte boundary.
@ -395,13 +391,11 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
of maximum size (i.e. 0FFFFh for a 16-bit segment or 0FFFFFFFFh for a 32-bit segment) or within 108 bytes of
maximum size, thus wrapping around to offset 0 of the segment. Since a wraparound situation is very abnormal
for a compiler or programmer to create, this does not affect a typical system.
 
Formally, the 80386 architecture does not permit an operand (coprocessor operands included) to wrap around
the end of a segment. If the user issues such an instruction nonetheless in a Protected Mode system, and
the operand starts and ends in valid, present pages of a segment, BUT spans through an invalid or inaccessible
page, the coprocessor may be put in an indeterminate state. In such cases, an FCLEX or FINIT instruction needs
to be executed before any other coprocessor instruction is issued.
 
**Workaround**: In Real Mode, this is not a problem since protection is not enabled. In Protected Mode,
this problem is avoided simply by not creating coprocessor operands which wrap around the end of the segment,
or by aligning the base of all segments on page boundaries.
@ -411,7 +405,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
Furthermore, if the Double Fault entry in the IDT is a trap gate, a shutdown results. In a related topic,
if the TSS Fault entry in the IDT is invalid for any reason (e.g. bad AR byte), then instead of a Double Fault
(exception 8), a shutdown results.
 
**Workaround**: A working system, one that creates TSS segments of adequate size to hold the processor state
(44 bytes for the TSS of a 16-bit task, 104 bytes for the TSS of a 32-bit task), will not encounter any problems
here. A working system should also provide a valid gate (interrupt, trap, or task gate) in the IDT for exception 8.
@ -422,37 +415,29 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
next even-numbered iteration. If the REP MOVS ends with an odd number of iterations, and single-stepping or data
breakpoints are enabled, then a single-step trap or data breakpoint trap on the final iteration will properly occur
after the final, odd-numbered iteration.
 
**Workaround**: When using the Trap Flag or data breakpoints with a debugger utility, this minor variation of
REP MOVS must be accepted, unless an effort is made to have the debugger emulate the REP MOVS rather than actually
execute it.
6. Task Switch to Virtual 8086 Mode Doesn't Update Prefetch Limit
**Problem**: When a task switch to Virtual 8086 Mode is performed, the prefetch limit is not updated to become 0FFFFh,
but instead remains at its previous value.
 
**Workaround**: Use the IRET instruction to transfer to Virtual 8086 Mode. Using IRET is the preferred method for
most instances, especially when the master OS dispatches a Virtual 8086 Mode program, because IRET can cause the
transition without a task switch.
7. Wrong Register Size for String Instructions in Mixed 16/32-bit Addressing Systems
**Problem**: If certain string and loop instructions are followed by instructions that either:
 
1) use a different address size (that is, if either the string instruction or the following instruction
uses an address size prefix), or
 
2) reference the stack (e.g. PUSH/POP/CALL/RET) and the "B" bit in the SS descriptor is different from the address size used by the string
instructions,
 
2) reference the stack (e.g. PUSH/POP/CALL/RET) and the "B" bit in the SS descriptor is different from the address
size used by the string instructions,
then one or more of [E]CX, [E]SI, or [E]DI is not updated properly. The size of the register (16 vs. 32) is
taken from the following instruction rather than from the string or loop instruction. This could result in
updating only the lower 16 bits of a 32-bit register, or in updating all 32 bits of a register being used as
16 bits. The instructions (and registers) affected by this are:
 
MOVS ([E]DI), REP MOVS ([E]SI), STOS ([E]DI), INS ([E]DI), and REP INS ([E]CX).
 
**Workaround**: No workaround is necessary if all code is 16-bit or if all code is 32-bit. The problem only
occurs if instructions with different address sizes are mixed together, or if a code segment of one size is used
with a stack segment of the other size.
 
In a system which mixes address sizes, add a NOP after each of the above instructions and ensure that the NOP
has the same address size as the string/loop (i.e., if the string/loop instruction includes an address prefix,
place the same address prefix before the NOP; conversely, if the string/loop instruction does not have an address
@ -464,19 +449,15 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
old code segment. This can allow execution beyond the end of the new segment without triggering a segment limit
violation. Or it can result in a spurious GP fault if the old and new segments overlap, and a prefetch occurs
beyond the limit of the old segment.
 
Note that the prefetch limit is checked on the linear address, not by comparing IP to 0FFFFh.
 
**Workaround**: All existing 8086 programs use only 16-bit addressing, and thus will not execute code at offsets
greater than 0FFFFh from the code segment base. Thus the lack of detection of walking off the end of a code segment
should not impact working 8086 programs.
 
A workaround to the spurious GP fault, if it occurs, is to simply IRET back to the faulting instruction, since the
IRET will correctly set the prefetch limit. If the fault handler has control of the single-step function, a very
simple workaround is to attempt to single-step the faulting instruction. If the single-step succeeded, the handler
could clear the fault, turn off single-stepping, and IRET. If a GP fault occurred attempting to single-step the
instruction, a "real" GP fault is the cause.
 
If the fault handler cannot access the single-stepping function, it still can check for "real" GP faults which must
be emulated by the master OS, for example, I/O instructions that need to be emulated, CLI/STI instructions that must
be emulated, etc. If none of these faults are recognized, the fault handler can assume this errata caused the GP fault
@ -484,7 +465,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
9. Page Fault Error Code on Stack Not Reliable
**Problem**: When a Page Fault (exception 14) occurs, the 3 defined bits in the error code may be unreliable
if a certain sequence of prefetch is happening at the same time.
 
**Workaround**: Although the page fault error code pushed onto the page fault handler's stack can be unreliable,
as described, the page fault linear address stored in register CR2 is always correct. The page fault handler should
refer to the page fault linear address in CR2 to access the corresponding page table entry and thereby determine
@ -494,23 +474,18 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
or accessing coprocessor ports (I/O addresses 800000F8h-800000FFh) as a result of executing coprocessor opcodes,
can generate incorrect I/O addresses if paging is enabled and the corresponding linear memory address is marked
"present" and "dirty."
 
Furthermore, when paging has been enabled and is then turned off, paging translation continues to occur for memory
or I/O cycles (I/O as described above) to linear addresses still stored in the TLB, but paging does not occur for
linear addresses that result in a TLB miss.
 
**Workaround**: Unless paging is used, this item is not a problem. If paging is used but all I/O ports are below
00001000h (as in a PC-DOS system), then I/O is no problem.
 
If paging is used and I/O ports exist in the range 0000l000h-0000FFFFh, then either have the memory pages at those
linear addresses marked "not present" (to avoid having those pages table entries cached in the TLB), or if "present,"
have those pages mapped such that bits 12-15 of the physical address equal bits 12-15 of the linear address.
Alternatively, re-assign any I/O ports in the range 00001000h-0000FFFFh to below 00001000h.
 
If paging is used and the coprocessor is also used, then have the memory page at linear address 80000xxxh either
marked "not present" (to avoid having that page table entry cached in the TLB), or if "present," have the page
mapped such that bit 31 (the most significant bit) of that page's physical address is a 1.
 
To completely disable 80386 paging when paging was previously enabled, the 80386 TLB should be flushed immediately
after resetting the~PG bit in CRO. The TLB can be flushed, you recall, by writing a Page Table Directory base address
to register CR3.
@ -521,7 +496,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
But in the case of a REP INS instruction, ECX is not updated correctly and is 0FFFFFFFFh (or CX is 0FFFFh in case of
16-bit operations). It should be noted that the REP INS executes the correct number of iterations and EDI (or DI)
is updated properly.
 
**Workaround**: After a REP INS instruction, do not rely on ECX (or CX) being zero. Hence, a new count (if any)
should be MOVed into ECX, rather than being ADDed into ECX.
12. NMI Doesn't Always Bring Chip Out of Shutdown in Obscure Condition with Paging Enabled
@ -530,51 +504,37 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
and a TLB miss occurs when accessing the null descriptor slot, the chip enters shutdown as it should in this case.
In this specific case however, an incoming NMI will not be able to bring the 386 out of shutdown. In this specific
case, only reset will bring the 386 out of shutdown.
 
**Workaround**: Ensure that the IDT gate for the Double Fault Handler has a non-null selectors for CS, and that
SS of the destination level is also non-null.
13. HOLD Input During Protected Mode Interlevel IRET when Paging is Enabled
**Problem**: Under specific situations involving paging and the page privilege bits, the HOLD input, and a RET
or IRET instruction performing an inter-level return to level 3, a problem can develop. These situations can be
avoided by the workarounds given.
 
The first situation, when the inner level stack (levels 0, 1, and 2) is not dword aligned (or not word aligned
in the case of a 16-bit [I]RET), requires that several conditions occur simultaneously:
 
1) Paging must be enabled, and the page table and directory entries for the inner level stacks must be marked
as supervisor access only.
 
2) The software must execute an inter-level RET or IRET to a Protected Mode program at privilege level 3.
An inter-level IRET to Virtual 8086 Mode does not exhibit this problem. An inter-level RET or IRET to level 1
or 2 does not exhibit this problem.
 
3) The inner level stack must be unaligned to a dword boundary (word boundary for a 16-bit [I]RET).
 
When the first situation occurs, a page fault (exception 14) occurs spuriously, indicating a page level
protection violation during a "user" level read of the inner level stack.
 
The second situation, whether or not the inner level stack is dword aligned (or word aligned in the case of a
16-bit [I]RET), also requires that several conditions occur simultaneously:
 
1) Paging must be enabled, and the page table and directory entries for the inner level stacks must be marked
as supervisor access only.
 
2) The software must execute an inter-level RET or IRET to a Protected Mode program at privilege level 3.
An inter-level IRET to Virtual 8086 Mode does not exhibit this problem. An inter-level RET or IRET to level 1
or 2 does not exhibit this problem.
 
3) The bus HOLD input must be asserted during the read, cycle which pops ESP (or SP) off the inner stack as a
result of a RET or IRET instruction.
 
When the second situation occurs, no exception is generated, but the processor will drive an incorrect physical
address during the read cycle in which SS is popped from the inner level stack.
 
**Workarounds**: A software workaround to both situations is to mark all pages which contain the inner level
stacks as user readable. This prevents either the first or second situation from occurring. The segmentation
system can be used to prevent user access to the linear addresses containing the inner-level stacks.
 
A workaround if not using the HOLD input is merely to keep the inner-level stacks aligned.
 
A Hardware workaround if using the HOLD input but not using the software workaround above is the following:
Since the problem occurs during the first cycle after a locked cycle to read the CS descriptor, a hardware
workaround is to prevent a HOLD request from hitting the processor during bus cycle following a LOCKed cycle.
@ -588,7 +548,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
perform a stack operation, such as PUSH or POP (see exact list below), the value of the [E]SP register may be
incorrect after the stack operation. Note that stack operations resulting from interrupts or exceptions following
LSL do update [E]SP correctly.
 
**Workaround**: Do not immediately follow the Protected Mode LSL instruction with any of the following stack
operation instructions: IRET (intra-task), POPA, POPF, POP (mem, reg, seg-reg), RET (intrasegment or intersegment),
CALL (direct intrasegment, direct intersegment, indirect intrasegment via reg), ENTER, PUSHA, PUSHF, PUSH (mem,
@ -600,7 +559,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
**Problem**: The Protected Mode instructions LSL, LAR, VERR or VERW executed with a null selector (i.e. bits
15 through 2 of the selector set to zero) as the operand will operate on the descriptor at entry 0 of the GDT
instead of unconditionally clearing the ZF flag.
 
**Workaround**: The "null descriptor" (i.e. the descriptor at entry 0 of the GDT) should be initialized to all
zeroes. If the "null descriptor" is initialized to all zeroes (i.e. an invalid value), the access made by these
instructions to the "null descriptor" will fail (since these instructions only operate on valid descriptors).
@ -610,18 +568,15 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
16. "Not Present" LDT in VM86 Task Raises Wrong Exception
**Problem**: A task switch to a VM86 task that has a "not present" LDT descriptor will cause a Segment Not Present
fault (exception 11) rather than an Invalid TSS fault (exception 10).
 
**Workaround**: The simplest workaround is to use a NULL selector for the LDT in a VM86 task, since the LDT is
not used when executing in Virtual 86 mode. However, if an interrupt or exception occurs, the processor will switch
out of Virtual 86 mode, into protected mode to handle the interrupt, without switching tasks. Thus, the operating
system should be structured so that all Interrupt and Trap gates active when executing a VM86 task reference segments
in the GDT.
 
If an LDT must be supplied for a task that executes in Virtual 86 mode, there are several easy workarounds. One
is to ensure that LDT segments are never marked "not present" in their segment descriptors. Paging is not affected
by this errata. LDT segments can be paged out and marked "not present" in their page descriptors in systems which
use paging.
 
If the operating system must mark the LDT segment descriptor "not present", the "not present" (exception 11)
handler must be able to handle the case of a "not present" LDT during a task switch. The "not present" exception
is reported with the LDT selector as the error code and with the VM bit set to 1 in the EFLAGS image of the caller.
@ -632,20 +587,14 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
and the second byte is located on a page or segment which would create a fault, then the processor will hang when
it tries to signal the fault. The processor remains stopped until an interrupt, NMI, or RESET occurs. This errata
applies only to coprocessor instructions in systems which use virtual memory.
 
**Workaround**: In virtual memory systems, the time-slice or watchdog timer provides an easy workaround, since a
timer interrupt will always cause the processor to begin interrupt processing. The timer routine should test the
following conditions to determine if this errata was encountered.
 
1) The saved CS:EIP must point within 8 bytes of the end of a page.
 
2) The last byte within the page must contain an ESC opcode.
 
3) All bytes between the saved CS:EIP and the ESC opcode must contain valid prefix opcodes (segment override 26h,
2Eh, 36h, 3Eh, 64h, 65h, address size override 67h, operand size override 66h).
 
4) The next page is not present, or not accessable.
 
If all four conditions are true, then the timer routine can assume this errata was encountered, and signal a page
fault, which will clear the condition. This workaround should be placed in the Operating System, so that applications
programs are unaffected.
@ -653,7 +602,6 @@ Here's what the world knew about 80386 problems in the B1 stepping, as of Decemb
**Problem**: If a second page fault occurs, while the processor is attempting to enter the service routine for the
first, then the processor will invoke the page fault (exception 14) handler a second time, rather than the double
fault (exception 8) handler. A subsequent fault, though, will lead to shutdown.
 
**Workaround**: No workaround is necessary in a working system.
An errata update dated March 26, 1987, produced internally by IBM rather than Intel, noted two additional

View file

@ -1134,6 +1134,7 @@ CPU.prototype.yieldCPU = function()
this.aCounts.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0; // this will break us out of stepCPU()
if (DEBUG) this.nSnapCycles = this.nBurstCycles;
/*
* The Debugger calls yieldCPU() after every message() to ensure browser responsiveness, but it looks
* odd for those messages to show CPU state changes but for the CPU's own status display to not (ditto

View file

@ -4115,9 +4115,11 @@ if (DEBUGGER) {
/*
* We must create a new aAddr from the address we obtained from aHistory, because
* aAddr was a reference, not a copy, and we don't want getInstruction() modifying the original.
*
* TODO: By using a new address for each iteration, history dumps fail to disassemble 32-bit overrides properly.
*/
aAddr = this.newAddr(aAddr[0], aAddr[1], aAddr[2]);
this.println(this.getInstruction(aAddr, "history", -n));
this.println(this.getInstruction(aAddr, "history", n));
if (++iHistory == aHistory.length) iHistory = 0;
this.nextHistory = --n;
cLines--;
@ -4384,7 +4386,7 @@ if (DEBUGGER) {
if (sCategory !== undefined) {
var bitsMessage = 0;
if (sCategory == "all") {
bitsMessage = (0xffffffff|0) & ~(Messages.HALT | Messages.LOG);
bitsMessage = (0xffffffff|0) & ~(Messages.HALT | Messages.KEYS | Messages.LOG);
sCategory = null;
} else if (sCategory == "on") {
fCriteria = true;
@ -4980,8 +4982,8 @@ if (DEBUGGER) {
* aAddr[5] to true whenever the address size is 32-bit. Initially, both fields must be set to match
* the size of the current code segment.
*/
aAddr[4] = (this.cpu.dataSize == 4);
aAddr[5] = (this.cpu.addrSize == 4);
aAddr[4] = (this.cpu.segCS.dataSize == 4);
aAddr[5] = (this.cpu.segCS.addrSize == 4);
fInitSize = false;
}
if (this.isPrefixIns(bOpcode)) {

View file

@ -2287,9 +2287,6 @@ Video.prototype.captureTouch = function()
*/
Video.prototype.onFocusChange = function(fFocus)
{
if (this.fHasFocus != fFocus && DEBUG && this.messageEnabled()) {
this.printMessage("onFocusChange(" + (fFocus? "true" : "false") + ")", true);
}
/*
* As per http://stackoverflow.com/questions/6740253/disable-scrolling-when-changing-focus-form-elements-ipad-web-app,
* I decided to try this work-around to prevent the webpage from scrolling around whenever the canvas is given

View file

@ -2863,7 +2863,7 @@ X86CPU.prototype.getLongPrefetch = function(addr)
*/
X86CPU.prototype.getWordPrefetch = function(addr)
{
return (I386 && this.addrSize == 4? this.getLongPrefetch(addr) : this.getShortPrefetch(addr));
return (I386 && this.dataSize == 4? this.getLongPrefetch(addr) : this.getShortPrefetch(addr));
};
/**
@ -3017,7 +3017,7 @@ X86CPU.prototype.getIPWord = function()
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMemHi);
}
this.regLIP += this.addrSize;
this.regLIP += this.dataSize;
if (this.regLIP > this.regLIPLimit) {
this.setIP(this.regLIP - this.segCS.base);
}

View file

@ -1337,16 +1337,13 @@ X86.fnRCLb = function RCLb(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
var shift = (src & this.nShiftCountMask) % 9;
shift %= 9;
if (!shift) {
carry <<= 7;
} else {
/*
* shift is 1-8, which means the new carry will come from the dst bit
* at position 7-0. To force it into position 7, left shift by (shift - 1).
*/
result = ((dst << shift) | (carry << (shift - 1)) | (dst >> (9 - shift))) & 0xff;
carry = dst << (shift - 1);
}
@ -1357,6 +1354,8 @@ X86.fnRCLb = function RCLb(dst, src)
};
/**
* fnRCLw(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL)
@ -1366,16 +1365,13 @@ X86.fnRCLw = function RCLw(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
var shift = (src & this.nShiftCountMask) % 17;
shift %= 17;
if (!shift) {
carry <<= 15;
} else {
/*
* shift is 1-16, which means the new carry will come from the dst bit
* at position 15-0. To force it into position 15, left shift by (shift - 1).
*/
result = ((dst << shift) | (carry << (shift - 1)) | (dst >> (17 - shift))) & 0xffff;
carry = dst << (shift - 1);
}
@ -1385,6 +1381,29 @@ X86.fnRCLw = function RCLw(dst, src)
return result;
};
/**
* fnRCLd(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL)
* @return {number}
*/
X86.fnRCLd = function RCLd(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
result = (dst << shift) | (carry << (shift - 1)) | (dst >>> (32 - shift));
carry = dst << (shift - 1);
X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD);
}
if (DEBUG && DEBUGGER) this.traceLog('RCLD', dst, src, flagsIn, this.getPS(), result);
return result;
};
/**
* fnRCRb(dst, src)
*
@ -1397,16 +1416,13 @@ X86.fnRCRb = function RCRb(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
var shift = (src & this.nShiftCountMask) % 9;
shift %= 9;
if (!shift) {
carry <<= 7;
} else {
/*
* shift is 1-8, which means the new carry will come from the dst bit
* at position 0-7. To force it into position 7, left shift by (8 - shift).
*/
result = ((dst >> shift) | (carry << (8 - shift)) | (dst << (9 - shift))) & 0xff;
carry = dst << (8 - shift);
}
@ -1428,16 +1444,13 @@ X86.fnRCRw = function RCRw(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
var shift = (src & this.nShiftCountMask) % 17;
shift %= 17;
if (!shift) {
carry <<= 15;
} else {
/*
* shift is 1-16, which means the new carry will come from the dst bit
* at position 0-15. To force it into position 15, left shift by (16 - shift).
*/
result = ((dst >> shift) | (carry << (16 - shift)) | (dst << (17 - shift))) & 0xffff;
carry = dst << (16 - shift);
}
@ -1447,6 +1460,29 @@ X86.fnRCRw = function RCRw(dst, src)
return result;
};
/**
* fnRCRd(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL)
* @return {number}
*/
X86.fnRCRd = function RCRd(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = this.getCarry();
result = (dst >>> shift) | (carry << (32 - shift)) | (dst << (33 - shift));
carry = dst << (32 - shift);
X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD);
}
if (DEBUG && DEBUGGER) this.traceLog('RCRD', dst, src, flagsIn, this.getPS(), result);
return result;
};
/**
* fnRETF(n)
*
@ -1497,23 +1533,13 @@ X86.fnROLb = function ROLb(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry;
/*
* The following mask obviates the need to use nShiftCountMask.
*/
var shift = src & 0x7;
shift &= 0x7;
if (!shift) {
/*
* shift is 8, which means the new carry will come from the dst bit
* at position 0.
*/
carry = dst << 7;
} else {
/*
* shift is 1-7, which means the new carry will come from the dst bit
* at position 7-1. To force it into position 7, left shift by (shift - 1).
*/
result = ((dst << shift) | (dst >> (8 - shift))) & 0xff;
carry = dst << (shift - 1);
}
@ -1535,19 +1561,13 @@ X86.fnROLw = function ROLw(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry;
/*
* The following mask obviates the need to use nShiftCountMask.
*/
var shift = src & 0xf;
shift &= 0xf;
if (!shift) {
carry = dst << 15;
} else {
/*
* shift is 1-15, which means the new carry will come from the dst bit
* at position 15-1. To force it into position 15, left shift by (shift - 1).
*/
result = ((dst << shift) | (dst >> (16 - shift))) & 0xffff;
carry = dst << (shift - 1);
}
@ -1569,22 +1589,13 @@ X86.fnRORb = function RORb(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry;
/*
* The following mask obviates the need to use nShiftCountMask.
*/
var shift = src & 0x7;
shift &= 0x7;
if (!shift) {
/*
* shift is 8, which means the new carry will come from the dst bit at position 7.
*/
carry = dst;
} else {
/*
* shift is 1-7, which means the new carry will come from the dst bit
* at position 0-6. To force it into position 7, left shift by (8 - shift).
*/
result = ((dst >> shift) | (dst << (8 - shift))) & 0xff;
carry = dst << (8 - shift);
}
@ -1606,22 +1617,13 @@ X86.fnRORw = function RORw(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry;
/*
* The following mask obviates the need to use nShiftCountMask.
*/
var shift = src & 0xf;
shift &= 0xf;
if (!shift) {
/*
* shift is 16, which means the new carry will come from dst bit 15.
*/
carry = dst;
} else {
/*
* shift is 1-15, which means the new carry will come from the dst bit
* at position 0-14. To force it into position 15, left shift by (16 - shift).
*/
result = ((dst >> shift) | (dst << (16 - shift))) & 0xffff;
carry = dst << (16 - shift);
}
@ -1645,12 +1647,10 @@ X86.fnRORw = function RORw(dst, src)
*/
X86.fnSARb = function SARb(dst, src)
{
if (src) {
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
if (src > 8) src = 9;
var temp = ((dst << 24) >> 24) >> (src - 1);
var shift = src & this.nShiftCountMask;
if (shift) {
if (shift > 8) shift = 9;
var temp = ((dst << 24) >> 24) >> (shift - 1);
dst = (temp >> 1) & 0xff;
this.setLogicResult(dst, X86.RESULT.BYTE, temp & 0x1);
}
@ -1671,12 +1671,10 @@ X86.fnSARb = function SARb(dst, src)
*/
X86.fnSARw = function SARw(dst, src)
{
if (src) {
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
if (src > 16) src = 17;
var temp = ((dst << 16) >> 16) >> (src - 1);
var shift = src & this.nShiftCountMask;
if (shift) {
if (shift > 16) shift = 17;
var temp = ((dst << 16) >> 16) >> (shift - 1);
dst = (temp >> 1) & 0xffff;
this.setLogicResult(dst, X86.RESULT.WORD, temp & 0x1);
}
@ -1796,15 +1794,13 @@ X86.fnSHLb = function SHLb(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = 0;
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
if (src > 8) {
if (shift > 8) {
result = 0;
} else {
carry = dst << (src - 1);
carry = dst << (shift - 1);
result = (carry << 1) & 0xff;
}
this.setLogicResult(result, X86.RESULT.BYTE, carry & X86.RESULT.BYTE, (result ^ carry) & X86.RESULT.BYTE);
@ -1829,15 +1825,13 @@ X86.fnSHLw = function SHLw(dst, src)
{
var result = dst;
var flagsIn = (DEBUG? this.getPS() : 0);
if (src) {
var shift = src & this.nShiftCountMask;
if (shift) {
var carry = 0;
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
if (src > 16) {
if (shift > 16) {
result = 0;
} else {
carry = dst << (src - 1);
carry = dst << (shift - 1);
result = (carry << 1) & 0xffff;
}
this.setLogicResult(result, X86.RESULT.WORD, carry & X86.RESULT.WORD, (result ^ carry) & X86.RESULT.WORD);
@ -1860,11 +1854,9 @@ X86.fnSHLw = function SHLw(dst, src)
*/
X86.fnSHRb = function SHRb(dst, src)
{
if (src) {
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
var temp = (src > 8? 0 : (dst >> (src - 1)));
var shift = src & this.nShiftCountMask;
if (shift) {
var temp = (shift > 8? 0 : (dst >> (shift - 1)));
dst = (temp >> 1) & 0xff;
this.setLogicResult(dst, X86.RESULT.BYTE, temp & 0x1, dst & X86.RESULT.BYTE);
}
@ -1885,11 +1877,9 @@ X86.fnSHRb = function SHRb(dst, src)
*/
X86.fnSHRw = function SHRw(dst, src)
{
if (src) {
/*
* The following comparison obviates the need to mask src with nShiftCountMask.
*/
var temp = (src > 16? 0 : (dst >> (src - 1)));
var shift = src & this.nShiftCountMask;
if (shift) {
var temp = (shift > 16? 0 : (dst >> (shift - 1)));
dst = (temp >> 1) & 0xffff;
this.setLogicResult(dst, X86.RESULT.WORD, temp & 0x1, dst & X86.RESULT.WORD);
}
@ -2323,6 +2313,8 @@ X86.fnXORw = function XORw(dst, src)
};
/**
* fnXORd(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@ -2334,6 +2326,21 @@ X86.fnXORd = function XORd(dst, src)
return this.setLogicResult(dst ^ src, X86.RESULT.DWORD);
};
/**
* fnTBD(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
X86.fnTBD = function TBD(dst, src)
{
this.printMessage("unimplemented 80386 opcode", true);
this.stopCPU();
return dst;
};
/**
* setRotateResult(result, carry, size)
*
@ -2355,43 +2362,57 @@ X86.setRotateResult = function(result, carry, size)
};
/**
* fnGRPCount1()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnGRPCount1 = function() {
X86.fnGRPCount1 = function()
{
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 2 : this.CYCLES.nOpCyclesShift1M);
return 1;
};
/**
* fnGRPCountCL()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnGRPCountCL = function() {
var count = this.regECX & this.nShiftCountMask;
X86.fnGRPCountCL = function()
{
var count = this.regECX & 0xff;
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS);
return count;
};
/**
* fnGRPCountImm()
*
* @this {X86CPU}
* @return {number}
*/
X86.fnGRPCountImm = function() {
X86.fnGRPCountImm = function()
{
var count = this.getIPByte();
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS);
return count;
};
/**
* fnGRPSrcNone()
*
* @this {X86CPU}
* @return {number|null}
*/
X86.fnGRPSrcNone = function() {
X86.fnGRPSrcNone = function()
{
return null;
};
/**
* fnGRPFault(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@ -2404,6 +2425,8 @@ X86.fnGRPFault = function(dst, src)
};
/**
* fnGRPInvalid(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@ -2416,6 +2439,8 @@ X86.fnGRPInvalid = function(dst, src)
};
/**
* fnGRPUndefined(dst, src)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src

View file

@ -1632,12 +1632,20 @@ X86.opINSw = function INSw()
}
if (nReps--) {
var addrFrom = this.regLIP - nDelta - 1;
var w = this.bus.checkPortInputNotify(this.regEDX, addrFrom);
if (BACKTRACK) this.backTrack.btiMemLo = this.backTrack.btiIO;
w |= (this.bus.checkPortInputNotify(this.regEDX, addrFrom) << 8);
if (BACKTRACK) this.backTrack.btiMemHi = this.backTrack.btiIO;
var w = 0, shift = 0;
for (var n = 0; n < this.dataSize; n++) {
w |= this.bus.checkPortInputNotify(this.regEDX, addrFrom) << shift;
shift += 8;
if (BACKTRACK) {
if (!n) {
this.backTrack.btiMemLo = this.backTrack.btiIO;
} else if (n == 1) {
this.backTrack.btiMemHi = this.backTrack.btiIO;
}
}
}
this.setSOWord(this.segES, this.regEDI & this.addrMask, w);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -1727,14 +1735,21 @@ X86.opOUTSw = function OUTSw()
}
if (nReps--) {
var w = this.getSOWord(this.segDS, this.regESI & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
var addrFrom = this.regLIP - nDelta - 1;
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemLo;
this.bus.checkPortOutputNotify(this.regEDX, w & 0xff, addrFrom);
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemHi;
this.bus.checkPortOutputNotify(this.regEDX, w >> 8, addrFrom);
var addrFrom = this.regLIP - nDelta - 1, shift = 0;
for (var n = 0; n < this.dataSize; n++) {
if (BACKTRACK) {
if (!n) {
this.backTrack.btiIO = this.backTrack.btiMemLo;
} else if (n == 1) {
this.backTrack.btiIO = this.backTrack.btiMemHi;
}
}
this.bus.checkPortOutputNotify(this.regEDX, (w >> shift) & 0xff, addrFrom);
shift += 8;
}
if (nReps) {
if (BUGS_8086) {
this.advanceIP(-2); // this instruction does not support segment overrides
@ -2542,15 +2557,15 @@ X86.opPOPF = function POPF()
X86.opSAHF = function SAHF()
{
/*
* NOTE: While it make LOOK more efficient to do this:
* NOTE: While it make seem more efficient to do this:
*
* this.setPS((this.getPS() & ~X86.PS.SAHF) | ((this.regEAX >> 8) & X86.PS.SAHF));
*
* the call to getPS() forces all the "indirect" flags to be resolved first, and then the call
* to setPS() forces them all to be recalculated, so on balance, the code below is probably more
* efficient, and may also avoid some unexpected side-effects of slamming the entire PS register.
* getPS() forces any "cached" flags to be resolved first, and setPS() must do extra work above
* and beyond setting the arithmetic and logical flags, so on balance, the code below may be more
* efficient, and may also avoid unexpected side-effects of updating the entire PS register.
*/
var ah = this.regEAX >> 8;
var ah = (this.regEAX >> 8) & 0xff;
if (ah & X86.PS.CF) this.setCF(); else this.clearCF();
if (ah & X86.PS.PF) this.setPF(); else this.clearPF();
if (ah & X86.PS.AF) this.setAF(); else this.clearAF();
@ -2567,7 +2582,7 @@ X86.opSAHF = function SAHF()
*/
X86.opLAHF = function LAHF()
{
this.regEAX = (this.regEAX & 0xff) | (this.getPS() & X86.PS.SAHF) << 8;
this.regEAX = (this.regEAX & ~0xff00) | (this.getPS() & X86.PS.SAHF) << 8;
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
};
@ -2681,7 +2696,7 @@ X86.opMOVSw = function MOVSw()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.CYCLES.nOpCyclesMovSr0;
}
if (nReps--) {
var nInc = ((this.regPS & X86.PS.DF)? -2 : 2);
var nInc = ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize);
this.setSOWord(this.segES, this.regEDI & this.addrMask, this.getSOWord(this.segData, this.regESI));
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + nInc) & this.addrMask);
@ -2761,7 +2776,7 @@ X86.opCMPSw = function CMPSw()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.CYCLES.nOpCyclesCmpSr0;
}
if (nReps--) {
var nInc = ((this.regPS & X86.PS.DF)? -2 : 2);
var nInc = ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize);
var wDst = this.getEAWord(this.segData, this.regESI & this.addrMask);
var wSrc = this.modEAWord(this.segES, this.regEDI & this.addrMask);
X86.fnCMPw.call(this, wDst, wSrc);
@ -2830,9 +2845,6 @@ X86.opSTOSb = function STOSb()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.CYCLES.nOpCyclesStoSr0;
}
if (nReps--) {
/*
* NOTE: We rely on setSOByte() to truncate regEAX to 8 bits; if setSOByte() changes, mask AX below.
*/
if (BACKTRACK) this.backTrack.btiMemLo = this.backTrack.btiAL;
this.setSOByte(this.segES, this.regEDI & this.addrMask, this.regEAX);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
@ -2877,7 +2889,7 @@ X86.opSTOSw = function STOSw()
this.backTrack.btiMemLo = this.backTrack.btiAL; this.backTrack.btiMemHi = this.backTrack.btiAH;
}
this.setSOWord(this.segES, this.regEDI & this.addrMask, this.regEAX);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2943,11 +2955,11 @@ X86.opLODSw = function LODSw()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.CYCLES.nOpCyclesLodSr0;
}
if (nReps--) {
this.regEAX = this.getSOWord(this.segData, this.regESI & this.addrMask);
this.regEAX = (this.regEAX & ~this.dataMask) | this.getSOWord(this.segData, this.regESI & this.addrMask);
if (BACKTRACK) {
this.backTrack.btiAL = this.backTrack.btiMemLo; this.backTrack.btiAH = this.backTrack.btiMemHi;
}
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -3020,8 +3032,8 @@ X86.opSCASw = function SCASw()
if (!(this.opPrefixes & X86.OPFLAG.REPEAT)) this.nStepCycles -= this.CYCLES.nOpCyclesScaSr0;
}
if (nReps--) {
X86.fnCMPw.call(this, this.regEAX, this.modEAWord(this.segES, this.regEDI & this.addrMask));
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
X86.fnCMPw.call(this, this.regEAX & this.dataMask, this.modEAWord(this.segES, this.regEDI & this.addrMask));
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -this.dataSize : this.dataSize)) & this.addrMask);
/*
* NOTE: As long as we're calling opGrpCMPb(), all our cycle times must be reduced by nOpCyclesArithRM
*/
@ -3269,6 +3281,16 @@ X86.opGrp2wi = function GRP2wi()
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnGRPCountImm);
};
/**
* op=0xC1 (GRP2 dword,imm16) (80186/80188 and up)
*
* @this {X86CPU}
*/
X86.opGrp2di = function GRP2di()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnGRPCountImm);
};
/**
* op=0xC2 (RET n)
*
@ -3502,6 +3524,16 @@ X86.opGrp2w1 = function GRP2w1()
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnGRPCount1);
};
/**
* op=0xD1 (GRP2 dword,1)
*
* @this {X86CPU}
*/
X86.opGrp2d1 = function GRP2d1()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnGRPCount1);
};
/**
* op=0xD2 (GRP2 byte,CL)
*
@ -3522,6 +3554,16 @@ X86.opGrp2wCL = function GRP2wCL()
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnGRPCountCL);
};
/**
* op=0xD3 (GRP2 dword,CL)
*
* @this {X86CPU}
*/
X86.opGrp2dCL = function GRP2dCL()
{
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnGRPCountCL);
};
/**
* op=0xD4 0x0A (AAM)
*
@ -4098,11 +4140,11 @@ X86.opUndefined = function()
};
/**
* opTBDd()
* opTBD()
*
* @this {X86CPU}
*/
X86.opTBDd = function()
X86.opTBD = function()
{
this.printMessage("unimplemented 80386 opcode", true);
this.stopCPU();
@ -4268,6 +4310,11 @@ X86.aOpGrp2w = [
X86.fnSHLw, X86.fnSHRw, X86.fnGRPUndefined, X86.fnSARw // 0xD1/0xD3(reg=0x4-0x7)
];
X86.aOpGrp2d = [
X86.fnTBD, X86.fnTBD, X86.fnRCLd, X86.fnRCRd, // 0xD1/0xD3(reg=0x0-0x3)
X86.fnTBD, X86.fnTBD, X86.fnGRPUndefined, X86.fnTBD // 0xD1/0xD3(reg=0x4-0x7)
];
X86.aOpGrp3b = [
X86.fnTEST8, X86.fnGRPUndefined, X86.fnNOTb, X86.fnNEGb, // 0xF6(reg=0x0-0x3)
X86.fnMULb, X86.fnIMULb, X86.fnDIVb, X86.fnIDIVb // 0xF6(reg=0x4-0x7)
@ -4290,32 +4337,35 @@ X86.aOpGrp4w = [
if (I386) {
/*
* Until we have *d() forms of all *w() opcode handlers, we need to put in placeholders (ie, opTBDd())
* Until we have *d() forms of all *w() opcode handlers, we need to put in placeholders (ie, opTBD())
*/
X86.aOpsD = {
0x01: X86.opTBDd, // opADDmd()
0x03: X86.opTBDd, // opADDrd()
0x05: X86.opTBDd, // opADDAXd()
0x09: X86.opTBDd, // opORmd()
0x0B: X86.opTBDd, // opORrd()
0x0D: X86.opTBDd, // opORAXd()
0x11: X86.opTBDd, // opADCmd()
0x13: X86.opTBDd, // opADCrd()
0x15: X86.opTBDd, // opADCAXd()
0x19: X86.opTBDd, // opSBBmd()
0x1B: X86.opTBDd, // opSBBrd()
0x1D: X86.opTBDd, // opSBBAXd()
0x01: X86.opTBD, // opADDmd()
0x03: X86.opTBD, // opADDrd()
0x05: X86.opTBD, // opADDAXd()
0x09: X86.opTBD, // opORmd()
0x0B: X86.opTBD, // opORrd()
0x0D: X86.opTBD, // opORAXd()
0x11: X86.opTBD, // opADCmd()
0x13: X86.opTBD, // opADCrd()
0x15: X86.opTBD, // opADCAXd()
0x19: X86.opTBD, // opSBBmd()
0x1B: X86.opTBD, // opSBBrd()
0x1D: X86.opTBD, // opSBBAXd()
0x21: X86.opANDmd,
0x23: X86.opANDrd,
0x25: X86.opANDAXd,
0x29: X86.opTBDd, // opSUBmd()
0x2B: X86.opTBDd, // opSUBrd()
0x2D: X86.opTBDd, // opSUBAXd()
0x31: X86.opTBDd, // opXORmd()
0x29: X86.opTBD, // opSUBmd()
0x2B: X86.opTBD, // opSUBrd()
0x2D: X86.opTBD, // opSUBAXd()
0x31: X86.opTBD, // opXORmd()
0x33: X86.opXORrd,
0x35: X86.opTBDd, // opXORAXd()
0x39: X86.opTBDd, // opCMPmd()
0x3B: X86.opTBDd, // opCMPrd()
0x3D: X86.opTBDd // opCMPAXd()
0x35: X86.opTBD, // opXORAXd()
0x39: X86.opTBD, // opCMPmd()
0x3B: X86.opTBD, // opCMPrd()
0x3D: X86.opTBD, // opCMPAXd()
0xC1: X86.opGrp2di,
0xD1: X86.opGrp2d1,
0xD3: X86.opGrp2dCL
};
}

View file

@ -216,7 +216,7 @@ X86Seg.loadIDTReal = function loadIDTReal(nIDT)
var addrIDT = cpu.addrIDT + (nIDT << 2);
var off = cpu.getShort(addrIDT);
cpu.regPS &= ~(X86.PS.TF | X86.PS.IF);
return this.load(cpu.getShort(addrIDT + 2)) + off;
return (this.load(cpu.getShort(addrIDT + 2)) + off)|0;
};
/**
@ -254,7 +254,7 @@ X86Seg.loadIDTProt = function loadIDTProt(nIDT)
*/
X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
{
return (this.base + off) | 0;
return (this.base + off)|0;
};
/**
@ -271,7 +271,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
*/
X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
{
return (this.base + off) | 0;
return (this.base + off)|0;
};
/**
@ -286,7 +286,7 @@ X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
X86Seg.checkReadProt = function checkReadProt(off, cb, fSuppress)
{
if (off + cb <= this.limit) {
return this.base + off;
return (this.base + off)|0;
}
return X86Seg.checkReadProtDisallowed.call(this, off, cb, fSuppress);
};
@ -303,7 +303,7 @@ X86Seg.checkReadProt = function checkReadProt(off, cb, fSuppress)
X86Seg.checkReadProtDown = function checkReadProtDown(off, cb, fSuppress)
{
if (off + cb > this.limit) {
return this.base + off;
return (this.base + off)|0;
}
return X86Seg.checkReadProtDisallowed.call(this, off, cb, fSuppress);
};
@ -337,7 +337,7 @@ X86Seg.checkReadProtDisallowed = function checkReadProtDisallowed(off, cb, fSupp
X86Seg.checkWriteProt = function checkWriteProt(off, cb, fSuppress)
{
if (off + cb <= this.limit) {
return this.base + off;
return (this.base + off)|0;
}
return X86Seg.checkWriteProtDisallowed.call(this, off, cb, fSuppress);
};
@ -354,7 +354,7 @@ X86Seg.checkWriteProt = function checkWriteProt(off, cb, fSuppress)
X86Seg.checkWriteProtDown = function checkWriteProtDown(off, cb, fSuppress)
{
if (off + cb > this.limit) {
return this.base + off;
return (this.base + off)|0;
}
return X86Seg.checkWriteProtDisallowed.call(this, off, cb, fSuppress);
};