Added Compaq DeskPro 386 ROMs

This commit is contained in:
Jeff Parsons 2015-02-22 15:42:54 -08:00 committed by jeffpar
commit eb196c3048
27 changed files with 5541 additions and 2285 deletions

View file

@ -113,24 +113,31 @@ function Bus(parmsBus, cpu, dbg)
* this.blockTotal Bus.BLOCK.TOTAL ((this.busLimit + this.blockSize) / this.blockSize) | 0
* this.blockMask Bus.BLOCK.MASK (this.blockTotal - 1) (ie, 0xff)
*
* Note that the blockShift calculation below chooses a 4Kb physical memory block size for a 20-bit bus
* (1Mb address space) and a 16Kb physical memory block for a 24-bit bus (16Mb address space). This yields
* a 256-block array for the smaller bus and a 1024-block array for the larger bus. If we left the block
* size at 4Kb in all cases, we'd end up with a 4096-block array for an 80286, which seems a bit excessive.
* Note that we choose a blockShift value (and thus a physical memory block size) based on "buswidth":
*
* I can't think of any reason why a coarser block granularity (of 16Kb) should hurt anything, other than
* wasting a little memory for ROMs smaller than the block size. Realize that this is strictly a physical
* memory implementation detail, which should have no bearing on segment or page granularity of any future
* virtual memory implementation.
* Bus Width Block Shift Block Size
* --------- ----------- ----------
* 20 bits (1Mb address space): 12 4Kb (256 maximum blocks)
* 24 bits (16Mb address space): 14 16Kb (1K maximum blocks)
* 32 bits (4Gb address space); 15 32Kb (128K maximum blocks)
*
* The coarser block granularities (ie, 16Kb and 32Kb) may cause problems for certain RAM and/or ROM
* allocations that are contiguous but are allocated out of order, or that have different controller
* requirements. Your choices, for the moment, are either to ensure the allocations are performed in
* order, or to choose smaller blockShift values (at the expense of a generating a larger block array).
*
* Be aware that this is strictly a physical memory implementation detail, which should have no bearing
* on segment or page granularity of any future virtual memory implementation.
*/
this.busLimit = this.busMask = (1 << this.nBusWidth) - 1;
this.blockShift = (this.nBusWidth <= 20? 12 : 14);
this.addrTotal = Math.pow(2, this.nBusWidth);
this.busLimit = this.busMask = (this.addrTotal - 1) | 0;
this.blockShift = (this.nBusWidth <= 20? 12 : (this.nBusWidth <= 24? 14 : 15));
this.blockSize = 1 << this.blockShift;
this.blockLen = this.blockSize >> 2;
this.blockLimit = this.blockSize - 1;
this.blockTotal = ((this.busLimit + this.blockSize) / this.blockSize) | 0;
this.blockTotal = (this.addrTotal / this.blockSize) | 0;
this.blockMask = this.blockTotal - 1;
this.assert(this.blockTotal <= Bus.BLOCK.NUM_MASK);
this.assert(this.blockMask <= Bus.BLOCK.NUM_MASK);
/*
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
@ -237,16 +244,16 @@ if (BACKTRACK) {
}
/*
* scanMemory() records block numbers in bits 0-14, a BackTrack "mod" bit in bit 15, and a block type at bit 28;
* scanMemory() records block numbers in bits 0-16, a BackTrack "mod" bit in bit 17, and a block type at bit 28;
* the bits reserved for a count are not used.
*/
Bus.BLOCK = {
NUM_SHIFT: 0,
NUM_MASK: 0x7fff,
BTMOD_SHIFT: 15,
NUM_MASK: 0x1ffff,
BTMOD_SHIFT: 17,
BTMOD_MASK: 0x1,
COUNT_SHIFT: 16,
COUNT_MASK: 0x0fff,
COUNT_SHIFT: 18,
COUNT_MASK: 0x03ff,
TYPE_SHIFT: 28,
TYPE_MASK: 0x7
};
@ -264,7 +271,7 @@ Bus.prototype.initMemory = function()
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) {
var addr = iBlock * this.blockSize;
var block = this.aMemBlocks[iBlock] = new Memory(addr);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, this.blockSize);
}
this.cpu.initMemory(this.aMemBlocks, this.blockShift, this.blockLimit, this.blockMask);
this.cpu.setAddressMask(this.busMask);
@ -309,35 +316,73 @@ Bus.prototype.powerUp = function(data, fRepower)
*
* Adds new Memory blocks to the specified address range. Any Memory blocks previously
* added to that range must first be removed via removeMemory(); otherwise, you'll get
* an allocation conflict error. Moreover, the address range must start at a block-granular
* address and span exactly one or more blocks; otherwise, you'll get a memory range error.
* an allocation conflict error. This helps prevent address calculation errors, redundant
* allocations, etc.
*
* These restrictions help prevent address calculation errors, redundant allocations, etc.
* We've relaxed some of the original requirements (ie, that addresses must start at a
* block-granular address, or that sizes must be equal to exactly one or more blocks), because
* machines with large block sizes can make it impossible to load certain ROMs at at their
* required addresses.
*
* Even so, Bus memory management does NOT provide a general-purpose heap. Most memory
* allocations occur during machine initialization and never change. The only notable
* exception is the Video frame buffer, which ranges from 4Kb (MDA) to 16Kb (CGA) to
* 32Kb/64Kb/128Kb (EGA), and only the EGA changes the buffer address post-initialization.
*
* Each Memory block keeps track of a single address (addr) and length (used), indicating
* the used space within the block; any free space that precedes or follows that used space
* can be allocated later, by simply extending the beginning or ending of the previously used
* space. However, any holes that might have existed between the original allocation and an
* extension are subsumed by the extension.
*
* @this {Bus}
* @param {number} addr is the starting physical address of the memory address range
* @param {number} size of the length in bytes of the range; must be a multiple of blockSize
* @param {number} addr is the starting physical address of the request
* @param {number} size of the request, in bytes
* @param {number} type is one of the Memory.TYPE constants
* @param {Object} [controller] is an optional memory controller component
* @return {boolean} true if successful, false if not
*/
Bus.prototype.addMemory = function(addr, size, type, controller)
{
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) {
var iBlock = addr >> this.blockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = this.aMemBlocks[iBlock];
if (block !== undefined && block.size) {
return this.reportError(1, addr, size);
var iBlock = addr >>> this.blockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = this.aMemBlocks[iBlock];
var addrBlock = iBlock * this.blockSize;
var sizeBlock = size > this.blockSize? this.blockSize : size;
if (block && block.size) {
if (block.type == type && block.controller == controller) {
/*
* Where there is already a block with a non-zero size, we can allow the allocation only if:
*
* 1) addr + size <= block.addr (the request precedes the used portion of the current block)
* or:
* 2) addr >= block.addr + block.used (the request follows the used portion of the current block)
*/
if (addr + size <= block.addr) {
block.used += (block.addr - addr);
block.addr = addr;
return true;
}
if (addr >= block.addr + block.used) {
var sizeAvail = block.size - (addr - addrBlock);
if (sizeAvail > size) sizeAvail = size;
block.used = addr - block.addr + sizeAvail;
size -= sizeAvail;
addr = addrBlock + this.blockSize;
continue;
}
}
addr = iBlock * this.blockSize;
block = this.aMemBlocks[iBlock++] = new Memory(addr, this.blockSize, type, controller);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize);
size -= this.blockSize;
return this.reportError(1, addr, size);
}
return true;
block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.blockSize, type, controller);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, this.blockSize);
size -= sizeBlock;
addr = addrBlock + this.blockSize;
}
return this.reportError(2, addr, size);
if (size > 0) {
return this.reportError(2, addr, size);
}
return true;
};
/**
@ -351,7 +396,7 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
Bus.prototype.cleanMemory = function(addr, size)
{
var fClean = true;
var iBlock = addr >> this.blockShift;
var iBlock = addr >>> this.blockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
if (this.aMemBlocks[iBlock].fDirty) {
this.aMemBlocks[iBlock].fDirty = fClean = false;
@ -384,7 +429,7 @@ Bus.prototype.cleanMemory = function(addr, size)
Bus.prototype.scanMemory = function(stats, addr, size)
{
if (addr == null) addr = 0;
if (size == null) size = (this.busLimit + 1) - addr;
if (size == null) size = (this.addrTotal - addr) | 0;
if (stats == null) stats = {cbTotal: 0, cBlocks: 0, aBlocks: new Array(this.blockTotal)};
var iBlock = addr >>> this.blockShift;
@ -470,7 +515,7 @@ Bus.prototype.getWidth = function()
Bus.prototype.setMemoryAccess = function(addr, size, afn)
{
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) {
var iBlock = addr >> this.blockShift;
var iBlock = addr >>> this.blockShift;
while (size > 0) {
var block = this.aMemBlocks[iBlock];
if (!block.controller) {
@ -490,6 +535,8 @@ Bus.prototype.setMemoryAccess = function(addr, size, afn)
*
* Replaces every block in the specified address range with empty Memory blocks that will ignore all reads/writes.
*
* TODO: Update the removeMemory() interface to reflect the relaxed requirements of the addMemory() interface.
*
* @this {Bus}
* @param {number} addr
* @param {number} size
@ -498,11 +545,11 @@ Bus.prototype.setMemoryAccess = function(addr, size, afn)
Bus.prototype.removeMemory = function(addr, size)
{
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) {
var iBlock = addr >> this.blockShift;
var iBlock = addr >>> this.blockShift;
while (size > 0) {
addr = iBlock * this.blockSize;
var block = this.aMemBlocks[iBlock++] = new Memory(addr);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, this.blockSize);
size -= this.blockSize;
}
return true;
@ -522,7 +569,7 @@ Bus.prototype.removeMemory = function(addr, size)
*/
Bus.prototype.getByte = function(addr)
{
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit);
};
/**
@ -536,7 +583,7 @@ Bus.prototype.getByte = function(addr)
*/
Bus.prototype.getByteDirect = function(addr)
{
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByteDirect(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByteDirect(addr & this.blockLimit);
};
/**
@ -553,7 +600,7 @@ Bus.prototype.getByteDirect = function(addr)
Bus.prototype.getShort = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readShort(off);
}
@ -572,7 +619,7 @@ Bus.prototype.getShort = function(addr)
Bus.prototype.getShortDirect = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readShortDirect(off);
}
@ -593,7 +640,7 @@ Bus.prototype.getShortDirect = function(addr)
Bus.prototype.getLong = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off);
}
@ -613,7 +660,7 @@ Bus.prototype.getLong = function(addr)
Bus.prototype.getLongDirect = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLongDirect(off);
}
@ -633,7 +680,7 @@ Bus.prototype.getLongDirect = function(addr)
*/
Bus.prototype.setByte = function(addr, b)
{
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
/**
@ -648,7 +695,7 @@ Bus.prototype.setByte = function(addr, b)
*/
Bus.prototype.setByteDirect = function(addr, b)
{
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff);
};
/**
@ -665,7 +712,7 @@ Bus.prototype.setByteDirect = function(addr, b)
Bus.prototype.setShort = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff);
return;
@ -687,7 +734,7 @@ Bus.prototype.setShort = function(addr, w)
Bus.prototype.setShortDirect = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff);
return;
@ -710,7 +757,7 @@ Bus.prototype.setShortDirect = function(addr, w)
Bus.prototype.setLong = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLong(off, l);
return;
@ -737,7 +784,7 @@ Bus.prototype.setLong = function(addr, l)
Bus.prototype.setLongDirect = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLongDirect(off, l);
return;
@ -857,7 +904,7 @@ Bus.prototype.writeBackTrackObject = function(addr, bto, off)
Bus.prototype.readBackTrack = function(addr)
{
if (BACKTRACK) {
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readBackTrack(addr & this.blockLimit);
}
return 0;
};
@ -873,7 +920,7 @@ Bus.prototype.writeBackTrack = function(addr, bti)
{
if (BACKTRACK) {
var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.blockLimit, bti);
var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
if (slot != slotPrev) {
@ -975,7 +1022,7 @@ Bus.prototype.updateBackTrackCode = function(addr, bti)
} else {
return;
}
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
}
};
@ -1145,7 +1192,7 @@ Bus.prototype.restoreMemory = function(a)
Bus.prototype.addMemBreak = function(addr, fWrite)
{
if (DEBUGGER) {
var iBlock = addr >> this.blockShift;
var iBlock = addr >>> this.blockShift;
this.aMemBlocks[iBlock].addBreakpoint(addr & this.blockLimit, fWrite);
}
};
@ -1160,7 +1207,7 @@ Bus.prototype.addMemBreak = function(addr, fWrite)
Bus.prototype.removeMemBreak = function(addr, fWrite)
{
if (DEBUGGER) {
var iBlock = addr >> this.blockShift;
var iBlock = addr >>> this.blockShift;
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.blockLimit, fWrite);
}
};

View file

@ -256,13 +256,13 @@ Component.subclass(Component, ChipSet);
/*
* Supported Models
*
* Unless otherwise noted, all BIOS references refer to the *original* BIOS released with each model
* Unless otherwise noted, all BIOS references refer to the *original* BIOS released with each model.
*/
ChipSet.MODEL_5150 = 5150; // used in reference to the 1st 5150 BIOS, dated Apr 24, 1981
ChipSet.MODEL_5160 = 5160; // used in reference to the 1st 5160 BIOS, dated Nov 8, 1982
ChipSet.MODEL_5170 = 5170; // used in reference to the 1st 5170 BIOS, dated Jan 10, 1984
/*
* The following are fake model numbers, used only to document issues/features of note in later BIOS revisions
* The following are fake model numbers, used only to document issues/features of note in later IBM PC AT BIOS revisions.
*/
ChipSet.MODEL_5170_REV2 = 5170.2; // used in reference to the 2nd 5170 BIOS, dated Jun 10, 1985
ChipSet.MODEL_5170_REV3 = 5170.3; // used in reference to the 3rd 5170 BIOS, dated Nov 15, 1985

View file

@ -249,7 +249,7 @@ CPU.prototype.powerUp = function(data, fRepower)
this.resetChecksum();
}
/*
* Give the Debugger a chance to do/print something once we've powered up (TODO: Review the necessity of this)
* Give the Debugger a chance to do/print something once we've powered up
*/
if (DEBUGGER && this.dbg) {
this.dbg.init();

View file

@ -251,7 +251,7 @@ if (DEBUGGER) {
*/
Debugger.INS = {
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
ARPL: 8, ASIZE: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
ARPL: 8, AS: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
@ -266,7 +266,7 @@ if (DEBUGGER) {
LFS: 104, LGDT: 105, LGS: 106, LIDT: 107, LLDT: 108, LMSW: 109, LOADALL:110, LOCK: 111,
LODSB: 112, LODSW: 113, LOOP: 114, LOOPNZ: 115, LOOPZ: 116, LSL: 117, LSS: 118, LTR: 119,
MOV: 120, MOVSB: 121, MOVSW: 122, MOVSX: 123, MOVZX: 124, MUL: 125, NEG: 126, NOP: 127,
NOT: 128, OR: 129, OSIZE: 130, OUT: 131, OUTS: 132, POP: 133, POPA: 134, POPF: 135,
NOT: 128, OR: 129, OS: 130, OUT: 131, OUTS: 132, POP: 133, POPA: 134, POPF: 135,
PUSH: 136, PUSHA: 137, PUSHF: 138, RCL: 139, RCR: 140, REPNZ: 141, REPZ: 142, RET: 143,
RETF: 144, ROL: 145, ROR: 146, SAHF: 147, SALC: 148, SAR: 149, SBB: 150, SCASB: 151,
SCASW: 152, SETBE: 153, SETC: 154, SETG: 155, SETGE: 156, SETL: 157, SETLE: 158, SETNBE: 159,
@ -686,8 +686,8 @@ if (DEBUGGER) {
/* 0x63 */ [Debugger.INS.ARPL, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_OUT, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN],
/* 0x64 */ [Debugger.INS.FS, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x65 */ [Debugger.INS.GS, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x66 */ [Debugger.INS.OSIZE, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x67 */ [Debugger.INS.ASIZE, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x66 */ [Debugger.INS.OS, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x67 */ [Debugger.INS.AS, Debugger.TYPE_NONE | Debugger.TYPE_386],
/* 0x68 */ [Debugger.INS.PUSH, Debugger.TYPE_IMM | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_286],
/* 0x69 */ [Debugger.INS.IMUL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_BOTH | Debugger.TYPE_286, Debugger.TYPE_MODRM | Debugger.TYPE_WORDIW | Debugger.TYPE_IN],
@ -1763,6 +1763,7 @@ if (DEBUGGER) {
Debugger.prototype.init = function()
{
this.println("Type ? for list of debugger commands");
this.updateStatus();
};
/**
@ -1878,7 +1879,7 @@ if (DEBUGGER) {
Debugger.prototype.stopCPU = function(s, fBlockFaults)
{
if (s) this.println(s);
this.cpu.stopCPU(!fBlockFaults);
if (this.cpu) this.cpu.stopCPU(!fBlockFaults);
};
/**
@ -1978,6 +1979,7 @@ if (DEBUGGER) {
{
this.historyInit();
this.cInstructions = 0;
this.sMessagePrev = null;
this.nCycles = 0;
this.aAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
/*
@ -2292,7 +2294,7 @@ if (DEBUGGER) {
* @param {Array} aAddr
* @param {boolean} [fWrite]
* @param {number} [cb] is number of extra bytes to check (0 or 1)
* @return {number} is the corresponding physical address, or -1 if there's an error
* @return {number} is the corresponding physical address, or X86.ADDR_INVALID
*/
Debugger.prototype.getAddr = function(aAddr, fWrite, cb)
{
@ -2312,9 +2314,11 @@ if (DEBUGGER) {
}
}
/*
* Map addresses in the top 64Kb (at the top of the 16Mb range) to the top of the 1Mb range.
* We used to map addresses at the top 64Kb of the first 16Mb to the top of the first 1Mb,
* but post-80286, that's no longer appropriate.
*
* if ((addr & 0xFF0000) == 0xFF0000) addr &= 0x0FFFFF;
*/
if ((addr & 0xFF0000) == 0xFF0000) addr &= 0x0FFFFF;
return addr;
};
@ -2335,7 +2339,7 @@ if (DEBUGGER) {
{
var b = 0xff;
var addr = this.getAddr(aAddr, false, 0);
if (addr >= 0) {
if (addr != X86.ADDR_INVALID) {
b = this.bus.getByteDirect(addr);
this.assert((b == (b & 0xff)), "invalid byte (" + b + ") at address: " + this.hexAddr(aAddr));
if (inc !== undefined) this.incAddr(aAddr, inc);
@ -2355,7 +2359,7 @@ if (DEBUGGER) {
{
var w = 0xffff;
var addr = this.getAddr(aAddr, false, 1);
if (addr >= 0) {
if (addr != X86.ADDR_INVALID) {
w = this.bus.getShortDirect(addr);
this.assert((w == (w & 0xffff)), "invalid word (" + w + ") at address: " + this.hexAddr(aAddr));
if (inc !== undefined) this.incAddr(aAddr, inc);
@ -2378,7 +2382,7 @@ if (DEBUGGER) {
Debugger.prototype.setByte = function(aAddr, b, inc)
{
var addr = this.getAddr(aAddr, true, 0);
if (addr >= 0) {
if (addr != X86.ADDR_INVALID) {
this.bus.setByteDirect(addr, b);
if (inc !== undefined) this.incAddr(aAddr, inc);
this.cpu.updateCPU();
@ -2396,7 +2400,7 @@ if (DEBUGGER) {
Debugger.prototype.setShort = function(aAddr, w, inc)
{
var addr = this.getAddr(aAddr, true, 1);
if (addr >= 0) {
if (addr != X86.ADDR_INVALID) {
this.bus.setShortDirect(addr, w);
if (inc !== undefined) this.incAddr(aAddr, inc);
this.cpu.updateCPU();
@ -2705,7 +2709,7 @@ if (DEBUGGER) {
var cOperands = 2;
var sOperands = "";
if (bOpcode >= X86.OPCODE.MOVSB && bOpcode <= X86.OPCODE.CMPSW || bOpcode >= X86.OPCODE.STOSB && bOpcode <= X86.OPCODE.SCASW) {
cOperands = 0; // HACK to suppress display of operands for the string instructions
cOperands = 0; // HACK to suppress display of operands for string instructions
}
for (var iOperand = 1; iOperand <= cOperands; iOperand++) {
@ -3032,7 +3036,7 @@ if (DEBUGGER) {
Debugger.prototype.getRegStr = function(fProt)
{
if (fProt === undefined) {
fProt = !!(this.cpu.regMSW & X86.MSW.PE);
fProt = !!(this.cpu.regCR0 & X86.CR0.MSW.PE);
}
var s = "AX=" + str.toHexWord(this.cpu.regEAX) +
" BX=" + str.toHexWord(this.cpu.regEBX) +
@ -3049,7 +3053,7 @@ if (DEBUGGER) {
this.getFlagStr("S") + this.getFlagStr("Z") + this.getFlagStr("A") + this.getFlagStr("P") + this.getFlagStr("C") +
" PS=" + str.toHexWord(this.cpu.getPS());
if (fProt) {
s += " MS=" + str.toHexWord(this.cpu.regMSW) + '\n' +
s += " MS=" + str.toHexWord(this.cpu.regCR0) + '\n' +
this.getDTRStr("LD", this.cpu.segLDT.sel, this.cpu.segLDT.base, this.cpu.segLDT.base + this.cpu.segLDT.limit) + ' ' +
this.getDTRStr("GD", null, this.cpu.addrGDT, this.cpu.addrGDTLimit) + ' ' +
this.getDTRStr("ID", null, this.cpu.addrIDT, this.cpu.addrIDTLimit) + " TR=" + str.toHexWord(this.cpu.segTSS.sel) +
@ -3073,10 +3077,11 @@ if (DEBUGGER) {
* convention for linear addresses and provide a different syntax (eg, "%%") physical memory references.
*
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
* done later, by getAddr(), which returns a negative result (-1) for invalid segments, out-of-range offsets,
* done later, by getAddr(), which returns X86.ADDR_INVALID for invalid segments, out-of-range offsets,
* etc. The Debugger's low-level get/set memory functions verify all getAddr() results, but even if an
* invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
* Bus.busLimit; in the case of -1, that will generally refer to the last byte of physical address space.
* Bus.busLimit; in the case of X86.ADDR_INVALID, that will generally refer to the top of the physical
* address space.
*
* @this {Debugger}
* @param {string|undefined} sAddr
@ -4592,8 +4597,8 @@ if (DEBUGGER) {
Debugger.prototype.doUnassemble = function(sAddr, sAddrEnd, n)
{
var aAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE);
if (aAddr[0] == null)
return;
if (aAddr[0] == null) return;
if (n === undefined) n = 1;
var aAddrEnd = this.newAddr(0xffff, aAddr[1], this.bus.busLimit);

View file

@ -71,7 +71,7 @@ var littleEndian = (TYPEDARRAYS? (function() {
})() : false);
/**
* Memory(addr, size, type, controller)
* Memory(addr, used, size, type, controller)
*
* The Bus component allocates Memory objects so that each has a memory buffer with a
* block-granular starting address and an address range equal to bus.blockSize; however,
@ -104,16 +104,19 @@ var littleEndian = (TYPEDARRAYS? (function() {
* is available).
*
* @constructor
* @param {number} addr of block (must be some multiple of bus.blockSize)
* @param {number} addr of lowest used address in block
* @param {number} [used] portion of block in bytes (0 for none); must be a multiple of 4
* @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4
* @param {number} [type] is one of the Memory.TYPE constants (default is Memory.TYPE.NONE)
* @param {Object} [controller] is an optional memory controller component
*/
function Memory(addr, size, type, controller)
function Memory(addr, used, size, type, controller)
{
var i;
this.adw = null;
this.offset = 0;
this.addr = addr;
this.used = used;
this.size = size || 0;
this.type = type || Memory.TYPE.NONE;
this.fReadOnly = (type == Memory.TYPE.ROM);
@ -172,7 +175,7 @@ function Memory(addr, size, type, controller)
/*
* If littleEndian is true, we can use ab[], aw[] and adw[] directly; well, we can use them
* whenever the offset is a multiple of 1, 2 or 4, respectively. Otherwise, we must fallback to
* dv.getUint8()/dv.setUint8(), dv.getUint16()/dv.setUint16() and db.getInt32()/dv.setInt32().
* dv.getUint8()/dv.setUint8(), dv.getUint16()/dv.setUint16() and dv.getInt32()/dv.setInt32().
*/
this.ab = new Uint8Array(this.buffer, 0, size);
this.aw = new Uint16Array(this.buffer, 0, size >> 1);
@ -937,21 +940,19 @@ Memory.prototype = {
this.writeLong = this.fReadOnly? Memory.writeNone : this.writeLongDirect;
},
/**
* setDebugInfo(cpu, dbg, addr, size)
* setDebugInfo(cpu, dbg, size)
*
* @this {Memory}
* @param {X86CPU|Component} cpu
* @param {Debugger|Component} dbg
* @param {number} addr of block
* @param {number} size of block
*/
setDebugInfo: function(cpu, dbg, addr, size) {
setDebugInfo: function(cpu, dbg, size) {
if (DEBUGGER) {
this.cpu = cpu;
this.dbg = dbg;
this.addr = addr;
this.cReadBreakpoints = this.cWriteBreakpoints = 0;
if (this.dbg) this.dbg.redoBreakpoints(addr, size);
if (this.dbg) this.dbg.redoBreakpoints(this.addr, size);
}
},
/**

View file

@ -79,15 +79,19 @@ var X86 = {
NT: 0x4000, // bit 14: Nested Task flag (always set on 8086/80186, clear on 80286 reset)
BIT15: 0x8000 // bit 15: reserved (always set on 8086/80186, clear otherwise)
},
/*
* Machine Status Word definitions (stored in regMSW)
*/
MSW: {
PE: 0x0001, // protected-mode enabled
MP: 0x0002, // monitor processor extension (ie, coprocessor)
EM: 0x0004, // emulate processor extension
TS: 0x0008, // task switch indicator
SET: 0xfff0 // on the 80286, these are always set (TODO: Verify)
CR0: {
/*
* Machine Status Word (MSW) bit definitions
*/
MSW: {
PE: 0x0001, // protected-mode enabled
MP: 0x0002, // monitor processor extension (ie, coprocessor)
EM: 0x0004, // emulate processor extension
TS: 0x0008, // task switch indicator
ON: 0xfff0 // on the 80286, these bits are always on (TODO: Verify)
},
ET: 0x00000010, // coprocessor type (80287 or 80387); always 1 on post-80386 CPUs
PG: 0x80000000|0 // 0: paging disabled
},
SEL: {
RPL: 0x0003, // requested privilege level (0-3)

View file

@ -101,8 +101,8 @@ function X86CPU(parmsCPU) {
var nCyclesDefault = 0;
switch(this.model) {
default:
case X86.MODEL_8088:
default:
nCyclesDefault = 4772727;
break;
case X86.MODEL_80286:
@ -701,6 +701,9 @@ X86CPU.prototype.initProcessor = function()
this.OPFLAG_NOINTR8086 = X86.OPFLAG.NOINTR;
this.nShiftCountMask = 0xff; // on an 8086/8088, all shift counts are used as-is
/*
* TODO: Create an 80386-specific CYCLES table.
*/
this.CYCLES = (this.model >= X86.MODEL_80286? X86CPU.CYCLES_80286 : X86CPU.CYCLES_8088);
this.aOps = X86OpXX.aOps.slice(); // make copies of aOps and others before modifying them
@ -818,12 +821,27 @@ X86CPU.prototype.resetRegs = function()
this.regESI = 0;
this.regEDI = 0;
/*
* The following are internal "registers" that are used to capture intermediate values inside selected helper
* functions and use them if they've been modified (or are known to always change); for example, the MUL and DIV
* instructions perform calculations that must be propagated to specific registers (eg, AX and/or DX), which
* the ModRM decoder functions don't know about. We initialize them here mainly for documentation purposes.
*/
this.regMD16 = this.regMD32 = -1;
/*
* Another internal "register" we occasionally need is an interim copy of bModRM, set inside selected opcode
* handlers so that the helper function can have access to the instruction's bModRM without resorting to a closure
* (which, in the Chrome V8 engine, for example, seems to cause constant recompilation).
*/
this.bModRM = 0;
/*
* NOTE: Even though the MSW and IDTR are 80286-specific, we initialize them for ALL CPUs, so that
* functions like X86Help.opHelpINT() can use the same code for both. The 8086/8088 have no direct way
* of accessing or changing them, so this internal change should be perfectly safe for those processors.
*/
this.regMSW = X86.MSW.SET;
this.regCR0 = X86.CR0.MSW.ON;
this.addrIDT = 0; this.addrIDTLimit = 0x03FF;
this.nIOPL = 0; // this should be set before the first setPS() call
@ -844,14 +862,62 @@ X86CPU.prototype.resetRegs = function()
this.segES = new X86Seg(this, X86Seg.ID.DATA, "ES");
this.segSS = new X86Seg(this, X86Seg.ID.STACK, "SS");
this.setSP(0);
this.setSS(0);
if (I386 && this.model >= X86.MODEL_80386) {
this.regCR0 = X86.CR0.ET;
this.segFS = new X86Seg(this, X86Seg.ID.DATA, "FS");
this.segGS = new X86Seg(this, X86Seg.ID.DATA, "GS");
}
this.segNULL = new X86Seg(this, X86Seg.ID.NULL, "NULL");
this.setCSIP(0, 0xFFFF); // this should be called before the first setPS() call
/*
* The next few initializations mirror what we must do prior to each instruction (ie, inside the stepCPU() function);
* note that opPrefixes, along with segData and segStack, are reset only after we've executed a non-prefix instruction.
*/
this.segData = this.segDS;
this.segStack = this.segSS;
this.opFlags = this.opPrefixes = 0;
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
/*
* intFlags contains some internal states we use to indicate whether a hardware interrupt (INTFLAG.INTR) or
* Trap software interrupt (INTR.TRAP) has been requested, as well as when we're in a "HLT" state (INTFLAG.HALT)
* that requires us to wait for a hardware interrupt (INTFLAG.INTR) before continuing execution.
*
* intFlags must be cleared only by checkINTR(), whereas opFlags must be cleared prior to every CPU operation.
*/
this.intFlags = X86.INTFLAG.NONE;
/*
* The following contain the (default) OPERAND size (2 for 16 bits, 4 for 32 bits), and the corresponding masks
* for isolating the (src) bits of an OPERAND and clearing the (dst) bits of an OPERAND. These are reset to
* their segCS counterparts at the start of every new instruction, but are also set here for documentation purposes.
*/
this.dataSize = this.segCS.dataSize;
this.dataMask = this.segCS.dataMask;
/*
* Similarly, the following contain the (default) ADDRESS size (2 for 16 bits, 4 for 32 bits), and the corresponding
* masks for isolating the (src) bits of an address and clearing the (dst) bits of an address. Like the OPERAND size
* properties, these are reset to their segCS counterparts at the start of every new instruction.
*/
this.addrSize = this.segCS.addrSize;
this.addrMask = this.segCS.addrMask;
/*
* It's also worth noting that instructions that implicitly use the stack also rely on something called STACK size,
* which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties:
*
* segSS.addrSize (2 or 4)
* segSS.addrMask (0xffff or 0xffffffff)
*
* As there is no STACK size instruction prefix override, there's no need to propagate these segSS properties
* to separate X86CPU properties, as we do for the OPERAND size and ADDRESS size properties.
*/
this.setCSIP(0, 0xffff); // this should be called before the first setPS() call
if (BACKTRACK) {
/*
@ -907,12 +973,12 @@ X86CPU.prototype.resetRegs = function()
/*
* TODO: Verify what the 80286 actually sets addrGDT and addrGDTLimit to on reset (or if it leaves them alone).
*/
this.addrGDT = 0; this.addrGDTLimit = 0xFFFF; // GDTR
this.addrGDT = 0; this.addrGDTLimit = 0xffff; // GDTR
this.segLDT = new X86Seg(this, X86Seg.ID.LDT, "LDT", true); // LDTR
this.segTSS = new X86Seg(this, X86Seg.ID.TSS, "TSS", true); // TR
this.segVER = new X86Seg(this, X86Seg.ID.OTHER, "VER", true); // a scratch segment register for VERR and VERW instructions
this.setCSIP(0xFFF0, 0xF000); // in real-mode, 0xF000 defaults the CS base address to 0x0F0000
this.setCSBase(0xFF0000); // which is why we must manually adjust the CS base address to 0xFF0000
this.setCSIP(0xfff0, 0xf000); // on an 80286 or 80386, the default CS:IP is 0xF000:0xFFF0 instead of 0xFFFF:0x0000
this.setCSBase(0xffff0000|0); // on an 80286 or 80386, all CS base address bits above bit 15 must be set
}
/*
@ -926,66 +992,6 @@ X86CPU.prototype.resetRegs = function()
*/
this.setProtMode();
/*
* intFlags contains some internal states we use to indicate whether a hardware interrupt (INTFLAG.INTR) or
* Trap software interrupt (INTR.TRAP) has been requested, as well as when we're in a "HLT" state (INTFLAG.HALT)
* that requires us to wait for a hardware interrupt (INTFLAG.INTR) before continuing execution.
*
* intFlags must be cleared only by checkINTR(), whereas opFlags must be cleared prior to every CPU operation.
*/
this.intFlags = X86.INTFLAG.NONE;
/*
* The following are internal "registers" that are used to capture intermediate values inside selected helper
* functions and use them if they've been modified (or are known to always change); for example, the MUL and DIV
* instructions perform calculations that must be propagated to specific registers (eg, AX and/or DX), which
* the ModRM decoder functions don't know about. We initialize them here mainly for documentation purposes.
*/
this.regMD16 = this.regMD32 = -1;
/*
* Another internal "register" we occasionally need is an interim copy of bModRM, set inside selected opcode
* handlers so that the helper function can have access to the instruction's bModRM without resorting to a closure
* (which, in the Chrome V8 engine, for example, seems to cause constant recompilation).
*/
this.bModRM = 0;
/*
* The next few initializations mirror what we must do prior to each instruction (ie, inside the stepCPU() function);
* note that opPrefixes, along with segData and segStack, are reset only after we've executed a non-prefix instruction.
*/
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
this.segData = this.segDS;
this.segStack = this.segSS;
this.opFlags = this.opPrefixes = 0;
/*
* The following contain the (default) OPERAND size (2 for 16 bits, 4 for 32 bits), and the corresponding masks
* for isolating the (src) bits of an OPERAND and clearing the (dst) bits of an OPERAND. These are reset to
* their segCS counterparts at the start of every new instruction, but are also set here for documentation purposes.
*/
this.dataSize = this.segCS.dataSize;
this.dataMask = this.segCS.dataMask;
/*
* Similarly, the following contain the (default) ADDRESS size (2 for 16 bits, 4 for 32 bits), and the corresponding
* masks for isolating the (src) bits of an address and clearing the (dst) bits of an address. Like the OPERAND size
* properties, these are reset to their segCS counterparts at the start of every new instruction.
*/
this.addrSize = this.segCS.addrSize;
this.addrMask = this.segCS.addrMask;
/*
* It's also worth noting that instructions that implicitly use the stack also rely on something called STACK size,
* which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties:
*
* segSS.addrSize (2 or 4)
* segSS.addrMask (0xffff or 0xffffffff)
*
* As there is no STACK size instruction prefix override, there's no need to propagate these segSS properties
* to separate X86CPU properties, as we do for the OPERAND size and ADDRESS size properties.
*/
/*
* The memory dispatch tables; opMem refers to the active set, based on the current OPERAND size (dataSize),
* which is based foremost on segCS.dataSize, but can also be overridden by an OPERAND size instruction prefix.
@ -1176,7 +1182,7 @@ X86CPU.prototype.checkIntReturn = function(addr)
X86CPU.prototype.setProtMode = function(fProt)
{
if (fProt === undefined) {
fProt = !!(this.regMSW & X86.MSW.PE);
fProt = !!(this.regCR0 & X86.CR0.MSW.PE);
}
if (!fProt) {
this.printMessage("returning to real-mode");
@ -1199,7 +1205,7 @@ X86CPU.prototype.setProtMode = function(fProt)
X86CPU.prototype.saveProtMode = function()
{
if (this.addrGDT != null) {
return [this.regMSW, this.addrGDT, this.addrGDTLimit, this.addrIDT, this.addrIDTLimit, this.segLDT.save(), this.segTSS.save(), this.nIOPL];
return [this.regCR0, this.addrGDT, this.addrGDTLimit, this.addrIDT, this.addrIDTLimit, this.segLDT.save(), this.segTSS.save(), this.nIOPL];
}
return null;
};
@ -1215,7 +1221,7 @@ X86CPU.prototype.saveProtMode = function()
X86CPU.prototype.restoreProtMode = function(a)
{
if (a && a.length) {
this.regMSW = a[0];
this.regCR0 = a[0];
this.addrGDT = a[1];
this.addrGDTLimit = a[2];
this.addrIDT = a[3];
@ -1278,11 +1284,16 @@ X86CPU.prototype.restore = function(data)
this.restoreProtMode(a[5]);
this.setPS(a[6]);
/*
* Since we're not using setCS() and setSS(), it's important to call setIP() and setSP() *after* the segCS
* and segSS loads, so that the CPU's linear IP and SP registers (regLIP and regLSP) will be updated properly.
* Since we're not using setCS(), it's important to call setIP() *after* segCS is restored, so that the
* CPU's linear IP register (regLIP) will be updated properly.
*/
this.setIP(a[0]);
/*
* It's also important to call setSP(), so that the linear SP register (regLSP) will be updated properly;
* we also need to call setSS(), to ensure that the lower and upper stack limits are properly initialized.
*/
this.setSP(regESP);
this.setSS(this.segSS.sel);
if (I386 && this.model >= X86.MODEL_80386) {
this.segFS.restore(a[7]);
this.segGS.restore(a[8]);
@ -1492,7 +1503,7 @@ X86CPU.prototype.setIP = function(off)
*/
X86CPU.prototype.setCSIP = function(off, sel, fCall)
{
this.assert(!this.addrMask || (off & this.addrMask) == off);
this.assert((off & this.addrMask) == off);
this.segCS.fCall = fCall;
/*
* We break this operation into the following discrete steps (eg, set IP, load CS, and then update IP) so
@ -1523,7 +1534,7 @@ X86CPU.prototype.setCSIP = function(off, sel, fCall)
X86CPU.prototype.setCSBase = function(addr)
{
var regIP = this.getIP();
this.segCS.setBase(addr);
addr = this.segCS.setBase(addr);
this.regLIP = addr + regIP;
this.regLIPLimit = addr + this.segCS.limit;
};
@ -1900,7 +1911,7 @@ X86CPU.prototype.setPS = function(regPS, cpl)
* This has the added benefit of relieving us from zeroing the effective IOPL (this.nIOPL) whenever
* we're in real-mode, since we're zeroing the incoming IOPL bits up front now.
*/
if (!(this.regMSW & X86.MSW.PE)) {
if (!(this.regCR0 & X86.CR0.MSW.PE)) {
regPS &= ~(X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
}
@ -2015,7 +2026,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
X86CPU.prototype.getByte = function(addr)
{
if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit);
};
/**
@ -2028,7 +2039,7 @@ X86CPU.prototype.getByte = function(addr)
X86CPU.prototype.getShort = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
/*
* On the 8088, it takes 4 cycles to read the additional byte REGARDLESS whether the address is odd or even.
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -2055,7 +2066,7 @@ X86CPU.prototype.getShort = function(addr)
X86CPU.prototype.getLong = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
if (BACKTRACK) {
this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
@ -2077,7 +2088,7 @@ X86CPU.prototype.getLong = function(addr)
X86CPU.prototype.setByte = function(addr, b)
{
if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
/**
@ -2090,7 +2101,7 @@ X86CPU.prototype.setByte = function(addr, b)
X86CPU.prototype.setShort = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
/*
* On the 8088, it takes 4 cycles to write the additional byte REGARDLESS whether the address is odd or even.
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -2119,7 +2130,7 @@ X86CPU.prototype.setShort = function(addr, w)
X86CPU.prototype.setLong = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >>> this.blockShift;
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (BACKTRACK) {
@ -2440,7 +2451,7 @@ X86CPU.prototype.getBytePrefetch = function(addr)
* with side-effects we may not want, and in any case, while it seemed to improve Safari's performance slightly,
* it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled.
*
* b = this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
* b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit);
* this.nBusCycles += 4;
* this.cbPrefetchValid = 0;
* this.addrPrefetchHead = (addr + 1) & this.busMask;
@ -2490,7 +2501,7 @@ X86CPU.prototype.fillPrefetch = function(n)
{
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
var addr = this.addrPrefetchHead;
var b = this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
var b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit);
this.aPrefetch[this.iPrefetchHead] = b | (addr << 8);
if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.addrPrefetchHead = (addr + 1) & this.busMask;
@ -2939,9 +2950,9 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
* back to the REP. To emulate this flawed behavior, turn on BUGS_8086.
*/
this.opLIP = this.regLIP;
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
this.segData = this.segDS;
this.segStack = this.segSS;
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
if (I386) {
this.dataSize = this.segCS.dataSize;

View file

@ -468,15 +468,15 @@ var X86Help = {
* This instruction is always allowed to set MSW.PE, but it cannot clear MSW.PE once set;
* therefore, we always OR the previous value of MSW.PE into the new value before loading.
*/
w |= (this.regMSW & X86.MSW.PE);
this.regMSW = (this.regMSW & X86.MSW.SET) | (w & ~X86.MSW.SET);
w |= (this.regCR0 & X86.CR0.MSW.PE);
this.regCR0 = (this.regCR0 & X86.CR0.MSW.ON) | (w & ~X86.CR0.MSW.ON);
/*
* Since the 80286 cannot return to real-mode via this instruction, the only transition we
* must worry about is to protected-mode. And don't worry, there's no harm calling setProtMode()
* if the CPU is already in protected-mode (we could certainly optimize the call out in that
* case, but this instruction isn't used frequently enough to warrant it).
*/
if (this.regMSW & X86.MSW.PE) this.setProtMode(true);
if (this.regCR0 & X86.CR0.MSW.PE) this.setProtMode(true);
},
/**
* opHelpCALLF(off, sel)
@ -577,7 +577,7 @@ var X86Help = {
* TODO: We assess a fixed cycle cost up front, because at the moment, switchTSS() doesn't assess anything.
*/
this.nStepCycles -= this.CYCLES.nOpCyclesIRet;
if (this.regMSW & X86.MSW.PE) {
if (this.regCR0 & X86.CR0.MSW.PE) {
if (this.regPS & X86.PS.NT) {
var addrNew = this.segTSS.base;
var sel = this.getShort(addrNew + X86.TSS.PREV_TSS);

View file

@ -165,7 +165,7 @@ var X86Op0F = {
/*
* TODO: LOADALL operation still needs to be verified in protected mode....
*/
if (DEBUG && DEBUGGER && (this.regMSW & X86.MSW.PE)) this.stopCPU();
if (DEBUG && DEBUGGER && (this.regCR0 & X86.CR0.MSW.PE)) this.stopCPU();
},
/**
* @this {X86CPU}
@ -177,7 +177,7 @@ var X86Op0F = {
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true);
return;
}
this.regMSW &= ~X86.MSW.TS;
this.regCR0 &= ~X86.CR0.MSW.TS;
this.nStepCycles -= 2;
},
/**
@ -429,7 +429,7 @@ var X86Op0F = {
*/
opSMSW: function(dst, src) {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1));
return this.regMSW;
return this.regCR0;
},
/**
* @this {X86CPU}

View file

@ -255,7 +255,7 @@ X86Seg.loadIDTProt = function loadIDTProt(nIDT)
*/
X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
{
return this.base + off;
return (this.base + off) | 0;
};
/**
@ -272,7 +272,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
*/
X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
{
return this.base + off;
return (this.base + off) | 0;
};
/**
@ -467,7 +467,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
cpu.setSP(cpu.getShort(addrNew + offSP));
cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT));
if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld);
cpu.regMSW |= X86.MSW.TS;
cpu.regCR0 |= X86.CR0.MSW.TS;
return true;
};
@ -760,16 +760,21 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
* setBase(addr)
*
* This is used in unusual situations where the base must be set independently; normally, the base
* is set according to the selector provided to load(), but there are a few cases where setBase() is
* required (eg, in resetRegs(), where the 80286 wants the real-mode CS selector to be 0xF000 but the
* CS base must be 0xFF0000).
* is set according to the selector provided to load(), but there are a few cases where setBase()
* is required.
*
* For example, in resetRegs(), the real-mode CS selector must be reset to 0xF000 for an 80286 or 80386,
* but the CS base must be set to 0x00FF0000 or 0xFFFF0000, respectively. To simplify life for setBase()
* callers, we allow them to specify 32-bit bases, which we then truncate to 24 bits as needed.
*
* @this {X86Seg}
* @param {number} addr
* @return {number} addr, truncated as needed
*/
X86Seg.prototype.setBase = function(addr)
{
this.base = addr;
if (this.cpu.model < X86.MODEL_80386) addr &= 0xffffff;
return this.base = addr;
};
/**
@ -825,7 +830,7 @@ X86Seg.prototype.restore = function(a)
X86Seg.prototype.updateMode = function(fProt)
{
if (fProt === undefined) {
fProt = !!(this.cpu.regMSW & X86.MSW.PE);
fProt = !!(this.cpu.regCR0 & X86.CR0.MSW.PE);
}
this.fExpDown = false;
if (fProt) {

View file

@ -996,7 +996,7 @@
<xsl:call-template name="component">
<xsl:with-param name="machine" select="$machine"/>
<xsl:with-param name="class">computer</xsl:with-param>
<xsl:with-param name="parms">,buswidth:'<xsl:value-of select="$buswidth"/>',resume:'<xsl:value-of select="$resume"/>',state:'<xsl:value-of select="$state"/>'</xsl:with-param>
<xsl:with-param name="parms">,buswidth:<xsl:value-of select="$buswidth"/>,resume:<xsl:value-of select="$resume"/>,state:'<xsl:value-of select="$state"/>'</xsl:with-param>
</xsl:call-template>
</xsl:template>

View file

@ -137,12 +137,12 @@ net.propagateParms = function(sURL, req)
/**
* encodeURL(sURL, req, fDebug)
*
* Used to encodes any URLs presented on the current page, using this 3-step process:
* Used to encodes any URLs presented on the current page, using this 3-step (um, 4-step) process:
*
* 1) Replace any backslashes with slashes, in case the URL was derived from a file system path
* 2) Remap links that begin with "static/" to the corresponding URL at "http://static.pcjs.org/"
* 3) Massage the result with net.propagateParms(), so that any special parameters are passed along
* 4) Transform any "htmlspecialchars" into the corresponding entities, to help ensure proper validation
* 3) Transform any "htmlspecialchars" into the corresponding entities, using encodeURI()
* 4) Massage the result with net.propagateParms(), so that any special parameters are passed along
*
* @param {string} sURL
* @param {Object} req is the web server's (ie, Express) request object, if any
@ -154,8 +154,9 @@ net.encodeURL = function(sURL, req, fDebug)
if (sURL) {
sURL = sURL.replace(/\\/g, '/');
if (!fDebug) {
if (sURL.match(/^[^:?]*static/)) {
sURL = "http://static.pcjs.org" + path.join(req.path, sURL).replace("/static/", "/");
if (sURL.match(/^[^:?]*static\//)) {
if (sURL.charAt(0) != '/') sURL = path.join(req.path, sURL);
sURL = "http://static.pcjs.org" + sURL.replace("/static/", "/");
}
}
return net.propagateParms(encodeURI(sURL), req);