Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2017-07-23 14:59:43 -07:00
commit 7b527399d8
15 changed files with 3156 additions and 2906 deletions

View file

@ -205,8 +205,8 @@ any foreseeable problems to future generations, because we've got more important
And on PC-DOS 1.00, does `SPEEDUP` actually speed things up? In the real world, it presumably did, but in
the world of emulation, there isn't any measurable difference, because hardware features like stepping rates and
head settling times are rarely simulated. As I suggested in my [last blog post](/blog/2017/07/15/), this is a
degree of authenticity that all emulators should strive for, and PCjs is no exception to that rule -- I just haven't
gotten around to it yet.
degree of authenticity that all emulators should strive for, and PCjs emulators are no exception to that rule -- I
just haven't gotten around to it yet.
### Epilogue
@ -220,25 +220,27 @@ implemented, along with the proper queuing of all *four* possible types of seria
NOTE: Serial I/O from DOS (ie, redirection to or from a COM port) already worked because DOS performs polled I/O
rather than interrupt-driven I/O. Additionally, when DOS terminates a line, it outputs both CR (0Dh) and LF (0Ah)
bytes, whereas BASIC outputs only CR; so, when a machine uses a <textarea> control for serial I/O, we
automatically convert transform stand-alone CR bytes into LF bytes.
bytes, whereas BASIC outputs only CR; so, when a machine uses a <textarea> control for serial I/O, PCx86
automatically adds an LF after any stand-alone CR.
Second, when `SPEEDUP` crashed on newer versions of DOS, an invalid stack pointer would be loaded, and I noticed
that I had neglected to fully implement stack wrap-around on 8086/8088 processors; specifically, in the case where the
stack pointer is *odd*.
Normally, when the stack pointer is *even*, it will smoothly auto-decrement from 0000h to FFFEh or auto-increment
from FFFEh to 0000h. However, when the stack pointer is *odd* and it reaches 0001h, the next PUSH on a 8086/8088 must
automatically store the high byte at 0000h and the low byte at FFFFh; similarly, when the stack pointer is FFFFh,
the next POP must fetch the low byte from FFFFh and the high byte from 0000h.
Normally, when the stack pointer is *even*, it will cross the stack segment's 64Kb boundary without incident, smoothly
auto-decrementing from 0000h to FFFEh or auto-incrementing from FFFEh to 0000h. However, when the stack pointer is
*odd* and it reaches 0001h, the next PUSH on an 8088 must automatically store the high byte at 0000h and the low
byte at FFFFh; similarly, when the stack pointer is FFFFh, the next POP must fetch the low byte from FFFFh and the high
byte from 0000h.
Most emulators simulating an 8086/8088 in real-mode actually use V86-mode, which doesn't support stack operands that
wrap around the top of the stack segment; V86-mode will throw an exception, and the machine is toast. PCjs makes more
of an effort simulate real-mode, so any PUSH or POP should work smoothly, regardless whether the stack pointer is even
or odd.
Most emulators simulating an 8086/8088 (aka real-mode) actually use V86-mode, which doesn't support stack operands that
straddle the top of the stack segment; V86-mode will throw an exception, and the machine is toast.
PCjs is still far from perfect. For example, instruction fetches that cross a 64K boundary are supposed to wrap around
to 0000h as well. That's not implemented yet, but stay tuned.
PCx86 makes more of an effort simulate real-mode, so any PUSH or POP should work properly, regardless whether the stack
pointer is even or odd. In fact, the same is true for any real-mode 16-bit access across a 64Kb boundary, stack-based
or otherwise. PCx86 will even execute real-mode instructions that wrap around a 64Kb boundary.
PCx86 does it all (except when it doesn't)!
*[@jeffpar](http://twitter.com/jeffpar)*
*Jul 21, 2017*

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -492,6 +492,8 @@ MarkOut.prototype.convertMD = function(sIndent)
cProps = 0;
} else {
if (cProps++) sValue += ',';
var match = sPropValue.match(/^"(.*)"$/);
if (match) sPropValue = match[1];
sValue += '"' + sPropName + '":"' + sPropValue + '"';
}
}

View file

@ -3776,7 +3776,7 @@ class DebuggerX86 extends Debugger {
} while (dbgAddrIns.addr != dbgAddr.addr);
}
sLine += Str.pad(sBytes, dbgAddrIns.fAddr32? 24 : 16);
sLine += Str.pad(sBytes, dbgAddrIns.fAddr32? 25 : 17);
sLine += Str.pad(sOpcode, 8);
if (sOperands) sLine += ' ' + sOperands;

View file

@ -428,6 +428,7 @@ var X86 = {
NOREAD: 0x0001, // disable memory reads for the remainder of the current instruction
NOWRITE: 0x0002, // disable memory writes for the remainder of the current instruction
NOINTR: 0x0004, // a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
WRAP: 0x0008, // a segment wrap-around has occurred (relevant to 8086/8088 only)
SEG: 0x0010, // segment override
LOCK: 0x0020, // lock prefix
REPZ: 0x0040, // repeat while Z (NOTE: this value MUST match PS.ZF; see opCMPSb/opCMPSw/opSCASb/opSCASw)

View file

@ -2266,11 +2266,12 @@ class X86CPU extends CPU {
var newLIP = (this.regLIP >>> 0) + inc;
if (newLIP > this.regLIPMax) {
/*
* There's no such thing as a GP fault on the 8086/8088, and I'm assuming that,
* on newer processors, when the segment limit is the maximum, it's OK for IP to wrap.
* There's no such thing as a GP fault on the 8086/8088, and I'm now assuming that,
* on newer processors, all attempts to fetch opcodes beyond the limit trigger a fault.
*/
if (this.model <= X86.MODEL_8088 || this.segCS.limit == this.segCS.maskAddr) {
if (this.model <= X86.MODEL_8088 /* || this.segCS.limit == this.segCS.maskAddr */) {
newLIP = this.segCS.base + ((newLIP - this.regLIPMax) & (I386? this.maskData : 0xffff));
if (inc == 2) this.opFlags |= X86.OPFLAG.WRAP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.GP_FAULT, 0);
}
@ -3326,15 +3327,25 @@ class X86CPU extends CPU {
* @this {X86CPU}
* @param {X86Seg} seg register (eg, segDS)
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
* @return {number} word (16-bit or 32-bit) value at that address
*/
getEAWord(seg, off)
{
var w;
this.segEA = seg;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = seg.checkRead(this.offEA, (I386? this.sizeData : 2));
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getWord(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(seg.checkRead(0, 1)) << 8);
}
else {
w = this.getWord(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -3351,11 +3362,22 @@ class X86CPU extends CPU {
*/
getEAShortData(off)
{
var w;
this.segEA = this.segData;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(this.segEA.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getShort(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -3372,11 +3394,22 @@ class X86CPU extends CPU {
*/
getEAShortStack(off)
{
var w;
this.segEA = this.segStack;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(this.segEA.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getShort(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -3452,7 +3485,19 @@ class X86CPU extends CPU {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
this.setShort(this.segEA.checkWrite(this.offEA, 2), w);
var addr = this.segEA.checkWrite(this.offEA, 2);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(this.segEA.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setShort(addr, w);
}
}
/**
@ -3484,10 +3529,18 @@ class X86CPU extends CPU {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
if (!I386) {
this.setShort(this.segEA.checkWrite(this.offEA, 2), w);
} else {
this.setWord(this.segEA.checkWrite(this.offEA, this.sizeData), w);
var addr = this.segEA.checkWrite(this.offEA, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(this.segEA.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setWord(addr, w);
}
}
@ -3518,11 +3571,20 @@ class X86CPU extends CPU {
*/
getSOWord(seg, off)
{
if (!I386) {
return this.getShort(seg.checkRead(off, 2));
} else {
return this.getWord(seg.checkRead(off, this.sizeData));
var w;
var addr = seg.checkRead(off, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(addr) | (this.getByte(seg.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getWord(addr);
}
return w;
}
/**
@ -3552,10 +3614,18 @@ class X86CPU extends CPU {
*/
setSOWord(seg, off, w)
{
if (!I386) {
this.setShort(seg.checkWrite(off, 2), w);
} else {
this.setWord(seg.checkWrite(off, this.sizeData), w);
var addr = seg.checkWrite(off, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(seg.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setWord(addr, w);
}
}
@ -3696,8 +3766,20 @@ class X86CPU extends CPU {
*/
getIPShort()
{
var w;
var newLIP = this.checkIP(2);
var w = (PREFETCH? this.getShortPrefetch() : this.getShort(this.regLIP));
if (PREFETCH) {
w = this.getShortPrefetch();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getShort(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(2), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);
@ -3714,8 +3796,20 @@ class X86CPU extends CPU {
*/
getIPAddr()
{
var w;
var newLIP = this.checkIP(this.sizeAddr);
var w = (PREFETCH? this.getAddr() : this.getAddr(this.regLIP));
if (PREFETCH) {
w = this.getAddr();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getAddr(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);
@ -3732,8 +3826,20 @@ class X86CPU extends CPU {
*/
getIPWord()
{
var w;
var newLIP = this.checkIP(this.sizeData);
var w = (PREFETCH? this.getWordPrefetch() : this.getWord(this.regLIP));
if (PREFETCH) {
w = this.getWordPrefetch();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getWord(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);

View file

@ -83,8 +83,8 @@ class X86Seg {
this.maskData = this.maskAddr = 0xffff;
this.loadV86 = this.loadReal;
this.checkReadV86 = this.checkReadReal;
this.checkWriteV86 = this.checkWriteReal;
this.checkReadV86 = this.checkReadWriteReal;
this.checkWriteV86 = this.checkReadWriteReal;
/*
* Preallocated object for "probed" segment loads
@ -109,14 +109,20 @@ class X86Seg {
*
* loadIDT() sets fCall to true unconditionally in protected-mode (fCall has no meaning in real-mode).
*/
if (this.id == 1) { // X86Seg.ID.CODE (don't use until it's defined, or the Closure Compiler won't inline it)
if (this.id == 1 /* X86Seg.ID.CODE */) { // don't use X86Seg.ID.CODE until it's defined, or the Closure Compiler won't inline it
this.offIP = 0;
this.fCall = null;
this.fStackSwitch = false;
this.awParms = new Array(32);
this.aCallBreaks = [];
}
this.updateMode(true, fProt);
if (this.id == 0 /* X86Seg.ID.NULL */) {
this.checkRead = this.checkReadWriteNone;
this.checkWrite = this.checkReadWriteNone;
}
}
/**
@ -301,34 +307,39 @@ class X86Seg {
}
/**
* checkReadReal(off, cb)
*
* TODO: Invoke X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
* also, determine whether helpFault() call should include an error code, since this is happening in real-mode.
* checkReadWriteNone(off, cb)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb is number of bytes to check (1, 2 or 4)
* @return {number} corresponding linear address if valid, or X86.ADDR_INVALID if error (TODO: No error conditions yet)
* @return {number} corresponding linear address
*/
checkReadReal(off, cb)
checkReadWriteNone(off, cb)
{
return (this.base + off)|0;
}
/**
* checkWriteReal(off, cb)
*
* TODO: Invoke X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
* also, determine whether helpFault() call should include an error code, since this is happening in real-mode.
* checkReadWriteReal(off, cb)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb is number of bytes to check (1, 2 or 4)
* @return {number} corresponding linear address if valid, or X86.ADDR_INVALID if error (TODO: No error conditions yet)
* @return {number} corresponding linear address
*/
checkWriteReal(off, cb)
checkReadWriteReal(off, cb)
{
/*
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/
if ((off >>> 0) + cb > this.offMax) {
if (this.cpu.model <= X86.MODEL_8088) {
this.cpu.opFlags |= X86.OPFLAG.WRAP;
} else {
X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT);
}
}
return (this.base + off)|0;
}
@ -1542,8 +1553,8 @@ class X86Seg {
*/
this.load = this.loadReal;
this.loadIDT = this.loadIDTReal;
this.checkRead = this.checkReadReal;
this.checkWrite = this.checkWriteReal;
this.checkRead = this.checkReadWriteReal;
this.checkWrite = this.checkReadWriteReal;
this.cpl = this.dpl = 0;
this.addrDesc = X86.ADDR_INVALID;
this.fStackSwitch = false;

View file

@ -5,19 +5,19 @@ permalink: /pubs/pc/reference/intel/80186/
---
Intel 80186/80188 CPU Information
---
---------------------------------
80186 Errata
---
------------
* TBD
80186 Undocumented Instructions
---
-------------------------------
* TBD
Assorted Publications
---
---------------------
* TBD

View file

@ -5,7 +5,7 @@ permalink: /pubs/pc/reference/intel/80286/real_mode/
---
Intel 80286 CPU: Real Mode Emulation
---
------------------------------------
[The following information is from an undated 15-page Intel document titled "Undocumented iAPX 286 Test Instruction",
pp. 4-12]
@ -148,7 +148,7 @@ cache base and limit loaded by [LOADALL](../loadall/) is used to generate physic
The WAIT instructions required by the 8087 before ESC instructions can be safely executed by the 80287.
Discrepancies from an iAPX 86/88 Using Emulation
---
------------------------------------------------
An 80286 cannot exactly emulate an 8086/88 in all possible cases. Most differences are due to the extra protection
checks made in the 80286 which are not made in the 8086/88. The discrepancies listed here are minor enough that very
@ -250,7 +250,7 @@ few programs will be affected.
RCR instructions are not restartable if their memory-based operand is in a write-protected segment.
Extending the Address Space of Current iAPX 86 Software
---
-------------------------------------------------------
Current iAPX 86 real mode programs can use the extended address space of the iAPX 286 in a limited manner.
To address the extended memory, [LOADALL](../loadall/) must be used to load the descriptor cache with an base address
@ -285,7 +285,7 @@ A semaphore must be placed around software that writes into the [LOADALL](../loa
the software can execute [LOADALL](../loadall/) without interruption.
Mixing Real Mode and Protected Mode
---
-----------------------------------
The 80286 can alternate between real mode and protected mode. Some programs could be executed in real mode in the
bottom megabyte of memory, while others execute in protected mode in the upper 15 Mbytes of memory. An external OR

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -4689,6 +4689,7 @@ var X86 = {
NOREAD: 0x0001, // disable memory reads for the remainder of the current instruction
NOWRITE: 0x0002, // disable memory writes for the remainder of the current instruction
NOINTR: 0x0004, // a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
WRAP: 0x0008, // a segment wrap-around has occurred (relevant to 8086/8088 only)
SEG: 0x0010, // segment override
LOCK: 0x0020, // lock prefix
REPZ: 0x0040, // repeat while Z (NOTE: this value MUST match PS.ZF; see opCMPSb/opCMPSw/opSCASb/opSCASw)
@ -12899,8 +12900,8 @@ class X86Seg {
this.maskData = this.maskAddr = 0xffff;
this.loadV86 = this.loadReal;
this.checkReadV86 = this.checkReadReal;
this.checkWriteV86 = this.checkWriteReal;
this.checkReadV86 = this.checkReadWriteReal;
this.checkWriteV86 = this.checkReadWriteReal;
/*
* Preallocated object for "probed" segment loads
@ -12925,14 +12926,20 @@ class X86Seg {
*
* loadIDT() sets fCall to true unconditionally in protected-mode (fCall has no meaning in real-mode).
*/
if (this.id == 1) { // X86Seg.ID.CODE (don't use until it's defined, or the Closure Compiler won't inline it)
if (this.id == 1 /* X86Seg.ID.CODE */) { // don't use X86Seg.ID.CODE until it's defined, or the Closure Compiler won't inline it
this.offIP = 0;
this.fCall = null;
this.fStackSwitch = false;
this.awParms = new Array(32);
this.aCallBreaks = [];
}
this.updateMode(true, fProt);
if (this.id == 0 /* X86Seg.ID.NULL */) {
this.checkRead = this.checkReadWriteNone;
this.checkWrite = this.checkReadWriteNone;
}
}
/**
@ -13117,34 +13124,39 @@ class X86Seg {
}
/**
* checkReadReal(off, cb)
*
* TODO: Invoke X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
* also, determine whether helpFault() call should include an error code, since this is happening in real-mode.
* checkReadWriteNone(off, cb)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb is number of bytes to check (1, 2 or 4)
* @return {number} corresponding linear address if valid, or X86.ADDR_INVALID if error (TODO: No error conditions yet)
* @return {number} corresponding linear address
*/
checkReadReal(off, cb)
checkReadWriteNone(off, cb)
{
return (this.base + off)|0;
}
/**
* checkWriteReal(off, cb)
*
* TODO: Invoke X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
* also, determine whether helpFault() call should include an error code, since this is happening in real-mode.
* checkReadWriteReal(off, cb)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb is number of bytes to check (1, 2 or 4)
* @return {number} corresponding linear address if valid, or X86.ADDR_INVALID if error (TODO: No error conditions yet)
* @return {number} corresponding linear address
*/
checkWriteReal(off, cb)
checkReadWriteReal(off, cb)
{
/*
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/
if ((off >>> 0) + cb > this.offMax) {
if (this.cpu.model <= X86.MODEL_8088) {
this.cpu.opFlags |= X86.OPFLAG.WRAP;
} else {
X86.helpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT);
}
}
return (this.base + off)|0;
}
@ -14358,8 +14370,8 @@ class X86Seg {
*/
this.load = this.loadReal;
this.loadIDT = this.loadIDTReal;
this.checkRead = this.checkReadReal;
this.checkWrite = this.checkWriteReal;
this.checkRead = this.checkReadWriteReal;
this.checkWrite = this.checkReadWriteReal;
this.cpl = this.dpl = 0;
this.addrDesc = X86.ADDR_INVALID;
this.fStackSwitch = false;
@ -16737,11 +16749,12 @@ class X86CPU extends CPU {
var newLIP = (this.regLIP >>> 0) + inc;
if (newLIP > this.regLIPMax) {
/*
* There's no such thing as a GP fault on the 8086/8088, and I'm assuming that,
* on newer processors, when the segment limit is the maximum, it's OK for IP to wrap.
* There's no such thing as a GP fault on the 8086/8088, and I'm now assuming that,
* on newer processors, all attempts to fetch opcodes beyond the limit trigger a fault.
*/
if (this.model <= X86.MODEL_8088 || this.segCS.limit == this.segCS.maskAddr) {
if (this.model <= X86.MODEL_8088 /* || this.segCS.limit == this.segCS.maskAddr */) {
newLIP = this.segCS.base + ((newLIP - this.regLIPMax) & (I386? this.maskData : 0xffff));
if (inc == 2) this.opFlags |= X86.OPFLAG.WRAP;
} else {
X86.helpFault.call(this, X86.EXCEPTION.GP_FAULT, 0);
}
@ -17797,15 +17810,25 @@ class X86CPU extends CPU {
* @this {X86CPU}
* @param {X86Seg} seg register (eg, segDS)
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
* @return {number} word (16-bit or 32-bit) value at that address
*/
getEAWord(seg, off)
{
var w;
this.segEA = seg;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = seg.checkRead(this.offEA, (I386? this.sizeData : 2));
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getWord(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(seg.checkRead(0, 1)) << 8);
}
else {
w = this.getWord(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -17822,11 +17845,22 @@ class X86CPU extends CPU {
*/
getEAShortData(off)
{
var w;
this.segEA = this.segData;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(this.segEA.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getShort(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -17843,11 +17877,22 @@ class X86CPU extends CPU {
*/
getEAShortStack(off)
{
var w;
this.segEA = this.segStack;
this.offEA = off & (I386? this.maskAddr : 0xffff);
this.regEA = this.segEA.checkRead(this.offEA, 2);
if (this.opFlags & (X86.OPFLAG.NOREAD | X86.OPFLAG.WRAP)) {
if (this.opFlags & X86.OPFLAG.NOREAD) return 0;
var w = this.getShort(this.regEA);
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regEA) | (this.getByte(this.segEA.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getShort(this.regEA);
}
if (BACKTRACK) {
this.backTrack.btiEALo = this.backTrack.btiMem0;
this.backTrack.btiEAHi = this.backTrack.btiMem1;
@ -17923,7 +17968,19 @@ class X86CPU extends CPU {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
this.setShort(this.segEA.checkWrite(this.offEA, 2), w);
var addr = this.segEA.checkWrite(this.offEA, 2);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(this.segEA.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setShort(addr, w);
}
}
/**
@ -17955,10 +18012,18 @@ class X86CPU extends CPU {
this.backTrack.btiMem0 = this.backTrack.btiEALo;
this.backTrack.btiMem1 = this.backTrack.btiEAHi;
}
if (!I386) {
this.setShort(this.segEA.checkWrite(this.offEA, 2), w);
} else {
this.setWord(this.segEA.checkWrite(this.offEA, this.sizeData), w);
var addr = this.segEA.checkWrite(this.offEA, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(this.segEA.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setWord(addr, w);
}
}
@ -17989,11 +18054,20 @@ class X86CPU extends CPU {
*/
getSOWord(seg, off)
{
if (!I386) {
return this.getShort(seg.checkRead(off, 2));
} else {
return this.getWord(seg.checkRead(off, this.sizeData));
var w;
var addr = seg.checkRead(off, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkReadReal(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(addr) | (this.getByte(seg.checkRead(0, 1)) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
w = this.getWord(addr);
}
return w;
}
/**
@ -18023,10 +18097,18 @@ class X86CPU extends CPU {
*/
setSOWord(seg, off, w)
{
if (!I386) {
this.setShort(seg.checkWrite(off, 2), w);
} else {
this.setWord(seg.checkWrite(off, this.sizeData), w);
var addr = seg.checkWrite(off, this.sizeData);
if (this.opFlags & X86.OPFLAG.WRAP) {
/*
* The WRAP flag must have been set by checkWriteReal(), so we also know that we're dealing with
* a 16-bit write, which allows us to make some simplifications here.
*/
this.setByte(addr, w);
this.setByte(seg.checkWrite(0, 1), w >> 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
else {
this.setWord(addr, w);
}
}
@ -18167,8 +18249,20 @@ class X86CPU extends CPU {
*/
getIPShort()
{
var w;
var newLIP = this.checkIP(2);
var w = (PREFETCH? this.getShortPrefetch() : this.getShort(this.regLIP));
if (PREFETCH) {
w = this.getShortPrefetch();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getShort(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(2), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);
@ -18185,8 +18279,20 @@ class X86CPU extends CPU {
*/
getIPAddr()
{
var w;
var newLIP = this.checkIP(this.sizeAddr);
var w = (PREFETCH? this.getAddr() : this.getAddr(this.regLIP));
if (PREFETCH) {
w = this.getAddr();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getAddr(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);
@ -18203,8 +18309,20 @@ class X86CPU extends CPU {
*/
getIPWord()
{
var w;
var newLIP = this.checkIP(this.sizeData);
var w = (PREFETCH? this.getWordPrefetch() : this.getWord(this.regLIP));
if (PREFETCH) {
w = this.getWordPrefetch();
} else if (!(this.opFlags & X86.OPFLAG.WRAP)) {
w = this.getWord(this.regLIP);
} else {
/*
* The WRAP flag must have been set by checkIP(), so we also know that we're dealing with
* a 16-bit read, which allows us to make some simplifications here.
*/
w = this.getByte(this.regLIP) | (this.getByte(newLIP - 1) << 8);
this.opFlags &= ~X86.OPFLAG.WRAP;
}
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMem0);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMem1);
@ -70181,7 +70299,7 @@ class DebuggerX86 extends Debugger {
} while (dbgAddrIns.addr != dbgAddr.addr);
}
sLine += Str.pad(sBytes, dbgAddrIns.fAddr32? 24 : 16);
sLine += Str.pad(sBytes, dbgAddrIns.fAddr32? 25 : 17);
sLine += Str.pad(sOpcode, 8);
if (sOperands) sLine += ' ' + sOperands;

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long