Update ACCESSED bits in GDT/LDT descriptors (finally)

This commit is contained in:
Jeff Parsons 2015-05-11 13:11:30 -07:00 committed by jeffpar
commit 5eed275008
7 changed files with 229 additions and 182 deletions

View file

@ -85,13 +85,13 @@ function Bus(parmsBus, cpu, dbg)
* *
* Regarding blockTotal, we want to avoid using block overflow expressions like: * Regarding blockTotal, we want to avoid using block overflow expressions like:
* *
* iBlock < this.blockTotal? iBlock : 0 * iBlock < this.nBlockTotal? iBlock : 0
* *
* As long as we know that blockTotal is a power of two (eg, 256 or 0x100, in the case of * As long as we know that blockTotal is a power of two (eg, 256 or 0x100, in the case of
* nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and * nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and
* rewrite the previous expression as: * rewrite the previous expression as:
* *
* iBlock & this.blockMask * iBlock & this.nBlockMask
* *
* Similarly, we mask addresses with busMask to enforce "A20 wrap" on 20-bit busses. * Similarly, we mask addresses with busMask to enforce "A20 wrap" on 20-bit busses.
* For larger busses, A20 wrap can be simulated by either clearing bit 20 of busMask or by * For larger busses, A20 wrap can be simulated by either clearing bit 20 of busMask or by
@ -99,16 +99,16 @@ function Bus(parmsBus, cpu, dbg)
* *
* Bus Property Old hard-coded values (when nBusWidth was always 20) * Bus Property Old hard-coded values (when nBusWidth was always 20)
* ------------ ---------------------------------------------------- * ------------ ----------------------------------------------------
* this.busLimit 0xfffff * this.nBusLimit 0xfffff
* this.busMask [same as busLimit] * this.nBusMask [same as busLimit]
* this.blockSize 4096 * this.nBlockSize 4096
* this.blockLen (this.blockSize >> 2) * this.nBlockLen (this.nBlockSize >> 2)
* this.blockShift 12 * this.nBlockShift 12
* this.blockLimit 0xfff * this.nBlockLimit 0xfff
* this.blockTotal ((this.busLimit + this.blockSize) / this.blockSize) | 0 * this.nBlockTotal ((this.nBusLimit + this.nBlockSize) / this.nBlockSize) | 0
* this.blockMask (this.blockTotal - 1) [ie, 0xff] * this.nBlockMask (this.nBlockTotal - 1) [ie, 0xff]
* *
* Note that we choose a blockShift value (and thus a physical memory block size) based on "buswidth": * Note that we choose a nBlockShift value (and thus a physical memory block size) based on "buswidth":
* *
* Bus Width Block Shift Block Size * Bus Width Block Shift Block Size
* --------- ----------- ---------- * --------- ----------- ----------
@ -119,19 +119,19 @@ function Bus(parmsBus, cpu, dbg)
* The coarser block granularities (ie, 16Kb and 32Kb) may cause problems for certain RAM and/or ROM * 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 * 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 * 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). * order, or to choose smaller nBlockShift values (at the expense of a generating a larger block array).
* *
* Note that if PAGEBLOCKS is set, then for a bus width of 32 bits, the block size is fixed at 4Kb. * Note that if PAGEBLOCKS is set, then for a bus width of 32 bits, the block size is fixed at 4Kb.
*/ */
this.addrTotal = Math.pow(2, this.nBusWidth); this.addrTotal = Math.pow(2, this.nBusWidth);
this.busLimit = this.busMask = (this.addrTotal - 1) | 0; this.nBusLimit = this.nBusMask = (this.addrTotal - 1) | 0;
this.blockShift = (PAGEBLOCKS && this.nBusWidth == 32 || this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15); this.nBlockShift = (PAGEBLOCKS && this.nBusWidth == 32 || this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15);
this.blockSize = 1 << this.blockShift; this.nBlockSize = 1 << this.nBlockShift;
this.blockLen = this.blockSize >> 2; this.nBlockLen = this.nBlockSize >> 2;
this.blockLimit = this.blockSize - 1; this.nBlockLimit = this.nBlockSize - 1;
this.blockTotal = (this.addrTotal / this.blockSize) | 0; this.nBlockTotal = (this.addrTotal / this.nBlockSize) | 0;
this.blockMask = this.blockTotal - 1; this.nBlockMask = this.nBlockTotal - 1;
this.assert(this.blockMask <= Bus.BlockInfo.num.mask); this.assert(this.nBlockMask <= Bus.BlockInfo.num.mask);
/* /*
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by * Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
@ -288,12 +288,12 @@ var BusInfo;
Bus.prototype.initMemory = function() Bus.prototype.initMemory = function()
{ {
var block = new Memory(); var block = new Memory();
this.aMemBlocks = new Array(this.blockTotal); this.aMemBlocks = new Array(this.nBlockTotal);
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) { for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
this.aMemBlocks[iBlock] = block; this.aMemBlocks[iBlock] = block;
} }
this.cpu.initMemory(this.aMemBlocks, this.blockShift); this.cpu.initMemory(this.aMemBlocks, this.nBlockShift);
this.cpu.setAddressMask(this.busMask); this.cpu.setAddressMask(this.nBusMask);
}; };
/** /**
@ -363,11 +363,11 @@ Bus.prototype.powerUp = function(data, fRepower)
*/ */
Bus.prototype.addMemory = function(addr, size, type, controller) Bus.prototype.addMemory = function(addr, size, type, controller)
{ {
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) { while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = this.aMemBlocks[iBlock]; var block = this.aMemBlocks[iBlock];
var addrBlock = iBlock * this.blockSize; var addrBlock = iBlock * this.nBlockSize;
var sizeBlock = size > this.blockSize? this.blockSize : size; var sizeBlock = size > this.nBlockSize? this.nBlockSize : size;
if (block && block.size) { if (block && block.size) {
if (block.type == type && block.controller == controller) { if (block.type == type && block.controller == controller) {
@ -388,18 +388,18 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
if (sizeAvail > size) sizeAvail = size; if (sizeAvail > size) sizeAvail = size;
block.used = addr - block.addr + sizeAvail; block.used = addr - block.addr + sizeAvail;
size -= sizeAvail; size -= sizeAvail;
addr = addrBlock + this.blockSize; addr = addrBlock + this.nBlockSize;
continue; continue;
} }
} }
return this.reportError(1, addr, size); return this.reportError(1, addr, size);
} }
block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.blockSize, type, controller); block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.nBlockSize, type, controller);
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
block.setDebugger(this.dbg, addr, this.blockSize); block.setDebugger(this.dbg, addr, this.nBlockSize);
} }
size -= sizeBlock; size -= sizeBlock;
addr = addrBlock + this.blockSize; addr = addrBlock + this.nBlockSize;
} }
if (size > 0) { if (size > 0) {
return this.reportError(2, addr, size); return this.reportError(2, addr, size);
@ -418,13 +418,13 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
Bus.prototype.cleanMemory = function(addr, size) Bus.prototype.cleanMemory = function(addr, size)
{ {
var fClean = true; var fClean = true;
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) { while (size > 0 && iBlock < this.aMemBlocks.length) {
if (this.aMemBlocks[iBlock].fDirty) { if (this.aMemBlocks[iBlock].fDirty) {
this.aMemBlocks[iBlock].fDirty = fClean = false; this.aMemBlocks[iBlock].fDirty = fClean = false;
this.aMemBlocks[iBlock].fDirtyEver = true; this.aMemBlocks[iBlock].fDirtyEver = true;
} }
size -= this.blockSize; size -= this.nBlockSize;
iBlock++; iBlock++;
} }
return fClean; return fClean;
@ -447,8 +447,8 @@ Bus.prototype.scanMemory = function(info, addr, size)
if (size == null) size = (this.addrTotal - addr) | 0; if (size == null) size = (this.addrTotal - addr) | 0;
if (info == null) info = {cbTotal: 0, cBlocks: 0, aBlocks: []}; if (info == null) info = {cbTotal: 0, cBlocks: 0, aBlocks: []};
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
var iBlockMax = ((addr + size - 1) >>> this.blockShift); var iBlockMax = ((addr + size - 1) >>> this.nBlockShift);
info.cbTotal = 0; info.cbTotal = 0;
info.cBlocks = 0; info.cBlocks = 0;
@ -473,7 +473,7 @@ Bus.prototype.scanMemory = function(info, addr, size)
*/ */
Bus.prototype.getA20 = function() Bus.prototype.getA20 = function()
{ {
return !this.aBlocks2Mb && this.busLimit == this.busMask; return !this.aBlocks2Mb && this.nBusLimit == this.nBusMask;
}; };
/** /**
@ -510,9 +510,9 @@ Bus.prototype.setA20 = function(fEnable)
} }
} }
else if (this.nBusWidth > 20) { else if (this.nBusWidth > 20) {
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0); var addrMask = (this.nBusMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.busMask) { if (addrMask != this.nBusMask) {
this.busMask = addrMask; this.nBusMask = addrMask;
if (this.cpu) this.cpu.setAddressMask(addrMask); if (this.cpu) this.cpu.setAddressMask(addrMask);
} }
} }
@ -544,15 +544,15 @@ Bus.prototype.getWidth = function()
*/ */
Bus.prototype.setMemoryAccess = function(addr, size, afn) Bus.prototype.setMemoryAccess = function(addr, size, afn)
{ {
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) { if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0) { while (size > 0) {
var block = this.aMemBlocks[iBlock]; var block = this.aMemBlocks[iBlock];
if (!block.controller) { if (!block.controller) {
return this.reportError(5, addr, size); return this.reportError(5, addr, size);
} }
block.setAccess(afn); block.setAccess(afn);
size -= this.blockSize; size -= this.nBlockSize;
iBlock++; iBlock++;
} }
return true; return true;
@ -574,15 +574,15 @@ Bus.prototype.setMemoryAccess = function(addr, size, afn)
*/ */
Bus.prototype.removeMemory = function(addr, size) Bus.prototype.removeMemory = function(addr, size)
{ {
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) { if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0) { while (size > 0) {
addr = iBlock * this.blockSize; addr = iBlock * this.nBlockSize;
var block = this.aMemBlocks[iBlock++] = new Memory(addr); var block = this.aMemBlocks[iBlock++] = new Memory(addr);
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
block.setDebugger(this.dbg, addr, this.blockSize); block.setDebugger(this.dbg, addr, this.nBlockSize);
} }
size -= this.blockSize; size -= this.nBlockSize;
} }
return true; return true;
} }
@ -600,10 +600,10 @@ Bus.prototype.removeMemory = function(addr, size)
Bus.prototype.getMemoryBlocks = function(addr, size) Bus.prototype.getMemoryBlocks = function(addr, size)
{ {
var aBlocks = []; var aBlocks = [];
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) { while (size > 0 && iBlock < this.aMemBlocks.length) {
aBlocks.push(this.aMemBlocks[iBlock++]); aBlocks.push(this.aMemBlocks[iBlock++]);
size -= this.blockSize; size -= this.nBlockSize;
} }
return aBlocks; return aBlocks;
}; };
@ -626,7 +626,7 @@ Bus.prototype.getMemoryBlocks = function(addr, size)
Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type) Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
{ {
var i = 0; var i = 0;
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) { while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = aBlocks[i++]; var block = aBlocks[i++];
this.assert(block); this.assert(block);
@ -634,13 +634,13 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
if (type !== undefined) { if (type !== undefined) {
var blockNew = new Memory(addr); var blockNew = new Memory(addr);
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
blockNew.setDebugger(this.dbg, addr, this.blockSize); blockNew.setDebugger(this.dbg, addr, this.nBlockSize);
} }
blockNew.clone(block, type); blockNew.clone(block, type);
block = blockNew; block = blockNew;
} }
this.aMemBlocks[iBlock++] = block; this.aMemBlocks[iBlock++] = block;
size -= this.blockSize; size -= this.nBlockSize;
} }
}; };
@ -655,7 +655,7 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
*/ */
Bus.prototype.getByte = function(addr) Bus.prototype.getByte = function(addr)
{ {
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr); return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
}; };
/** /**
@ -669,7 +669,7 @@ Bus.prototype.getByte = function(addr)
*/ */
Bus.prototype.getByteDirect = function(addr) Bus.prototype.getByteDirect = function(addr)
{ {
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByteDirect(addr & this.blockLimit, addr); return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readByteDirect(addr & this.nBlockLimit, addr);
}; };
/** /**
@ -683,12 +683,12 @@ Bus.prototype.getByteDirect = function(addr)
*/ */
Bus.prototype.getShort = function(addr) Bus.prototype.getShort = function(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off != this.blockLimit) { if (off != this.nBlockLimit) {
return this.aMemBlocks[iBlock].readShort(off, addr); return this.aMemBlocks[iBlock].readShort(off, addr);
} }
return this.aMemBlocks[iBlock++].readByte(off, addr) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0, addr + 1) << 8); return this.aMemBlocks[iBlock++].readByte(off, addr) | (this.aMemBlocks[iBlock & this.nBlockMask].readByte(0, addr + 1) << 8);
}; };
/** /**
@ -702,12 +702,12 @@ Bus.prototype.getShort = function(addr)
*/ */
Bus.prototype.getShortDirect = function(addr) Bus.prototype.getShortDirect = function(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off != this.blockLimit) { if (off != this.nBlockLimit) {
return this.aMemBlocks[iBlock].readShortDirect(off, addr); return this.aMemBlocks[iBlock].readShortDirect(off, addr);
} }
return this.aMemBlocks[iBlock++].readByteDirect(off, addr) | (this.aMemBlocks[iBlock & this.blockMask].readByteDirect(0, addr + 1) << 8); return this.aMemBlocks[iBlock++].readByteDirect(off, addr) | (this.aMemBlocks[iBlock & this.nBlockMask].readByteDirect(0, addr + 1) << 8);
}; };
/** /**
@ -721,13 +721,13 @@ Bus.prototype.getShortDirect = function(addr)
*/ */
Bus.prototype.getLong = function(addr) Bus.prototype.getLong = function(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off, addr); return this.aMemBlocks[iBlock].readLong(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0, addr + 3) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.nBlockMask].readLong(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -741,13 +741,13 @@ Bus.prototype.getLong = function(addr)
*/ */
Bus.prototype.getLongDirect = function(addr) Bus.prototype.getLongDirect = function(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
return this.aMemBlocks[iBlock].readLongDirect(off, addr); return this.aMemBlocks[iBlock].readLongDirect(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLongDirect(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLongDirect(0, addr + 3) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLongDirect(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.nBlockMask].readLongDirect(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -761,7 +761,7 @@ Bus.prototype.getLongDirect = function(addr)
*/ */
Bus.prototype.setByte = function(addr, b) Bus.prototype.setByte = function(addr, b)
{ {
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff, addr); this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeByte(addr & this.nBlockLimit, b & 0xff, addr);
}; };
/** /**
@ -776,7 +776,7 @@ Bus.prototype.setByte = function(addr, b)
*/ */
Bus.prototype.setByteDirect = function(addr, b) Bus.prototype.setByteDirect = function(addr, b)
{ {
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff, addr); this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeByteDirect(addr & this.nBlockLimit, b & 0xff, addr);
}; };
/** /**
@ -790,14 +790,14 @@ Bus.prototype.setByteDirect = function(addr, b)
*/ */
Bus.prototype.setShort = function(addr, w) Bus.prototype.setShort = function(addr, w)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off != this.blockLimit) { if (off != this.nBlockLimit) {
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr); this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr); this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff, addr + 1); this.aMemBlocks[iBlock & this.nBlockMask].writeByte(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -812,14 +812,14 @@ Bus.prototype.setShort = function(addr, w)
*/ */
Bus.prototype.setShortDirect = function(addr, w) Bus.prototype.setShortDirect = function(addr, w)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off != this.blockLimit) { if (off != this.nBlockLimit) {
this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff, addr); this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByteDirect(off, w & 0xff, addr); this.aMemBlocks[iBlock++].writeByteDirect(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByteDirect(0, (w >> 8) & 0xff, addr + 1); this.aMemBlocks[iBlock & this.nBlockMask].writeByteDirect(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -833,9 +833,9 @@ Bus.prototype.setShortDirect = function(addr, w)
*/ */
Bus.prototype.setLong = function(addr, l) Bus.prototype.setLong = function(addr, l)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
this.aMemBlocks[iBlock].writeLong(off, l); this.aMemBlocks[iBlock].writeLong(off, l);
return; return;
} }
@ -843,7 +843,7 @@ Bus.prototype.setLong = function(addr, l)
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLong(off, addr); lPrev = this.aMemBlocks[iBlock].readLong(off, addr);
this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr); this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.nBlockMask;
addr += 3; addr += 3;
lPrev = this.aMemBlocks[iBlock].readLong(0, addr); lPrev = this.aMemBlocks[iBlock].readLong(0, addr);
this.aMemBlocks[iBlock].writeLong(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr); this.aMemBlocks[iBlock].writeLong(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr);
@ -861,9 +861,9 @@ Bus.prototype.setLong = function(addr, l)
*/ */
Bus.prototype.setLongDirect = function(addr, l) Bus.prototype.setLongDirect = function(addr, l)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
this.aMemBlocks[iBlock].writeLongDirect(off, l, addr); this.aMemBlocks[iBlock].writeLongDirect(off, l, addr);
return; return;
} }
@ -871,7 +871,7 @@ Bus.prototype.setLongDirect = function(addr, l)
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLongDirect(off, addr); lPrev = this.aMemBlocks[iBlock].readLongDirect(off, addr);
this.aMemBlocks[iBlock].writeLongDirect(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr); this.aMemBlocks[iBlock].writeLongDirect(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.nBlockMask;
addr += 3; addr += 3;
lPrev = this.aMemBlocks[iBlock].readLongDirect(0, addr); lPrev = this.aMemBlocks[iBlock].readLongDirect(0, addr);
this.aMemBlocks[iBlock].writeLongDirect(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr); this.aMemBlocks[iBlock].writeLongDirect(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr);
@ -983,7 +983,7 @@ Bus.prototype.writeBackTrackObject = function(addr, bto, off)
Bus.prototype.readBackTrack = function(addr) Bus.prototype.readBackTrack = function(addr)
{ {
if (BACKTRACK) { if (BACKTRACK) {
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readBackTrack(addr & this.blockLimit); return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readBackTrack(addr & this.nBlockLimit);
} }
return 0; return 0;
}; };
@ -999,8 +999,8 @@ Bus.prototype.writeBackTrack = function(addr, bti)
{ {
if (BACKTRACK) { if (BACKTRACK) {
var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT; var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.blockLimit, bti); var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.nBlockLimit, bti);
var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT; var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
if (slot != slotPrev) { if (slot != slotPrev) {
this.aMemBlocks[iBlock].modBackTrack(true); this.aMemBlocks[iBlock].modBackTrack(true);
@ -1101,7 +1101,7 @@ Bus.prototype.updateBackTrackCode = function(addr, bti)
} else { } else {
return; return;
} }
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeBackTrack(addr & this.blockLimit, bti); this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeBackTrack(addr & this.nBlockLimit, bti);
} }
}; };
@ -1204,7 +1204,7 @@ Bus.prototype.saveMemory = function()
{ {
var i = 0; var i = 0;
var a = []; var a = [];
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) { for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
var block = this.aMemBlocks[iBlock]; var block = this.aMemBlocks[iBlock];
/* /*
* We have to check both fDirty and fDirtyEver, because we may have called cleanMemory() on some of * We have to check both fDirty and fDirtyEver, because we may have called cleanMemory() on some of
@ -1243,8 +1243,8 @@ Bus.prototype.restoreMemory = function(a)
for (i = 0; i < a.length - 1; i += 2) { for (i = 0; i < a.length - 1; i += 2) {
var iBlock = a[i]; var iBlock = a[i];
var adw = a[i+1]; var adw = a[i+1];
if (adw && adw.length < this.blockLen) { if (adw && adw.length < this.nBlockLen) {
adw = State.decompress(adw, this.blockLen); adw = State.decompress(adw, this.nBlockLen);
} }
var block = this.aMemBlocks[iBlock]; var block = this.aMemBlocks[iBlock];
if (!block || !block.restore(adw)) { if (!block || !block.restore(adw)) {
@ -1271,8 +1271,8 @@ Bus.prototype.restoreMemory = function(a)
Bus.prototype.addMemBreak = function(addr, fWrite) Bus.prototype.addMemBreak = function(addr, fWrite)
{ {
if (DEBUGGER) { if (DEBUGGER) {
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
this.aMemBlocks[iBlock].addBreakpoint(addr & this.blockLimit, fWrite); this.aMemBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
} }
}; };
@ -1286,8 +1286,8 @@ Bus.prototype.addMemBreak = function(addr, fWrite)
Bus.prototype.removeMemBreak = function(addr, fWrite) Bus.prototype.removeMemBreak = function(addr, fWrite)
{ {
if (DEBUGGER) { if (DEBUGGER) {
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.blockLimit, fWrite); this.aMemBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
} }
}; };

View file

@ -903,8 +903,8 @@ if (DEBUGGER) {
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN], 0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_OUT | Debugger.TYPE_80286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286], 0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286],
0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286], 0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286],
0x20: [Debugger.INS.MOV, Debugger.TYPE_MODRM | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN], 0x20: [Debugger.INS.MOV, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_DWORD | Debugger.TYPE_IN], 0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_REG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386], 0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386], 0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386], 0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
@ -1282,7 +1282,7 @@ if (DEBUGGER) {
if (MAXDEBUG) this.chipset = cmp.getComponentByType("ChipSet"); if (MAXDEBUG) this.chipset = cmp.getComponentByType("ChipSet");
this.cchAddr = bus.getWidth() >> 2; this.cchAddr = bus.getWidth() >> 2;
this.maskAddr = bus.busLimit; this.maskAddr = bus.nBusLimit;
this.aaOpDescs = Debugger.aaOpDescs; this.aaOpDescs = Debugger.aaOpDescs;
if (this.cpu.model >= X86.MODEL_80186) { if (this.cpu.model >= X86.MODEL_80186) {
@ -1790,7 +1790,7 @@ if (DEBUGGER) {
for (var i = 0; i < this.cpu.aMemBlocks.length; i++) { for (var i = 0; i < this.cpu.aMemBlocks.length; i++) {
var block = this.cpu.aBusBlocks[i]; var block = this.cpu.aBusBlocks[i];
if (block.type === Memory.TYPE.NONE) continue; if (block.type === Memory.TYPE.NONE) continue;
this.println(str.toHex(block.id) + " %" + str.toHex(i << this.cpu.blockShift) + ": " + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + Memory.TYPE.NAMES[block.type]); this.println(str.toHex(block.id) + " %" + str.toHex(i << this.cpu.nBlockShift) + ": " + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + Memory.TYPE.NAMES[block.type]);
} }
}; };
@ -3620,7 +3620,7 @@ if (DEBUGGER) {
* done later, by getAddr(), which returns X86.ADDR_INVALID 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 * 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 * invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
* Bus.busLimit; in the case of X86.ADDR_INVALID, that will generally refer to the top of the physical * Bus.nBusLimit; in the case of X86.ADDR_INVALID, that will generally refer to the top of the physical
* address space. * address space.
* *
* @this {Debugger} * @this {Debugger}
@ -3794,7 +3794,7 @@ if (DEBUGGER) {
* should be relocated to the top 64Kb of the first 1Mb, so that we're immune from any changes * should be relocated to the top 64Kb of the first 1Mb, so that we're immune from any changes
* to the A20 line. * to the A20 line.
*/ */
if ((dbgAddr.addr & ~0xffff) == (this.bus.busLimit & ~0xffff)) { if ((dbgAddr.addr & ~0xffff) == (this.bus.nBusLimit & ~0xffff)) {
dbgAddr.addr &= 0x000fffff; dbgAddr.addr &= 0x000fffff;
} }
symbol['p'] = dbgAddr.addr; symbol['p'] = dbgAddr.addr;
@ -5209,7 +5209,7 @@ if (DEBUGGER) {
if (dbgAddr.off == null) return; if (dbgAddr.off == null) return;
if (n === undefined) n = 1; if (n === undefined) n = 1;
var dbgAddrEnd = this.newAddr(this.maskReg, dbgAddr.sel, this.bus.busLimit); var dbgAddrEnd = this.newAddr(this.maskReg, dbgAddr.sel, this.bus.nBusLimit);
var cb = 0x100; var cb = 0x100;
if (sAddrEnd !== undefined) { if (sAddrEnd !== undefined) {

View file

@ -59,8 +59,8 @@ var littleEndian = (TYPEDARRAYS? (function() {
* Memory(addr, used, size, type, controller) * Memory(addr, used, size, type, controller)
* *
* The Bus component allocates Memory objects so that each has a memory buffer with a * 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, * block-granular starting address and an address range equal to bus.nBlockSize; however,
* the size of any given Memory object's underlying buffer can be either zero or bus.blockSize; * the size of any given Memory object's underlying buffer can be either zero or bus.nBlockSize;
* memory read/write functions for empty (buffer-less) blocks are mapped to readNone/writeNone. * memory read/write functions for empty (buffer-less) blocks are mapped to readNone/writeNone.
* *
* The Bus allocates empty blocks for the entire address space during initialization, so that * The Bus allocates empty blocks for the entire address space during initialization, so that
@ -239,6 +239,19 @@ Memory.TYPE = {
*/ */
Memory.idBlock = 0; Memory.idBlock = 0;
/**
* adjustEndian(dw)
*
* @param {number} dw
* @return {number}
*/
Memory.adjustEndian = function(dw) {
if (TYPEDARRAYS && !littleEndian) {
dw = (dw << 24) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | (dw >>> 24);
}
return dw;
};
Memory.prototype = { Memory.prototype = {
constructor: Memory, constructor: Memory,
parent: null, parent: null,
@ -467,19 +480,6 @@ Memory.prototype = {
this.dbg.redoBreakpoints(addr, size); this.dbg.redoBreakpoints(addr, size);
} }
}, },
/**
* adjustEndian(dw)
*
* @this {Memory}
* @param {number} dw
* @return {number}
*/
adjustEndian: function(dw) {
if (TYPEDARRAYS && !littleEndian) {
dw = (dw << 24) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | (dw >>> 24);
}
return dw;
},
/** /**
* getPageBlock(addr, fWrite) * getPageBlock(addr, fWrite)
* *
@ -513,8 +513,8 @@ Memory.prototype = {
this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index) this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index)
this.blockPTE = blockPTE; this.blockPTE = blockPTE;
this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index) this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index)
this.bitPTEDirty = this.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY); this.bitPTEDirty = Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY);
this.bitPTEAccessed = this.adjustEndian(X86.PTE.ACCESSED); this.bitPTEAccessed = Memory.adjustEndian(X86.PTE.ACCESSED);
}, },
/** /**
* addBreakpoint(off, fWrite) * addBreakpoint(off, fWrite)

View file

@ -487,8 +487,8 @@ Panel.prototype.findAddress = function(x, y)
y -= rect.y; y -= rect.y;
var region = this.busInfo.aRegions[i]; var region = this.busInfo.aRegions[i];
var iBlock = usr.getBitField(Bus.BlockInfo.num, this.busInfo.aBlocks[region.iBlock]); var iBlock = usr.getBitField(Bus.BlockInfo.num, this.busInfo.aBlocks[region.iBlock]);
var addr = iBlock * this.bus.blockSize; var addr = iBlock * this.bus.nBlockSize;
var addrLimit = (iBlock + region.cBlocks) * this.bus.blockSize - 1; var addrLimit = (iBlock + region.cBlocks) * this.bus.nBlockSize - 1;
/* /*
* If you want memory to be arranged "vertically" instead of "horizontally", do this: * If you want memory to be arranged "vertically" instead of "horizontally", do this:
@ -528,7 +528,7 @@ Panel.prototype.updateAnimation = function()
/* /*
* Calculate the pixel-to-memory-address ratio * Calculate the pixel-to-memory-address ratio
*/ */
this.ratioMemoryToPixels = (this.busInfo.cBlocks * this.bus.blockSize) / (Panel.LIVEMEM.CX * Panel.LIVEMEM.CY); this.ratioMemoryToPixels = (this.busInfo.cBlocks * this.bus.nBlockSize) / (Panel.LIVEMEM.CX * Panel.LIVEMEM.CY);
/* /*
* Update the BusInfo object with region information (cRegions and aRegions); return true if region * Update the BusInfo object with region information (cRegions and aRegions); return true if region
* information has changed since the last call. * information has changed since the last call.
@ -568,7 +568,7 @@ Panel.prototype.updateAnimation = function()
rect = this.busInfo.aRects[i]; rect = this.busInfo.aRects[i];
rect.drawWith(this.contextLiveMem, Memory.TYPE.COLORS[region.type]); rect.drawWith(this.contextLiveMem, Memory.TYPE.COLORS[region.type]);
this.centerPen(rect); this.centerPen(rect);
this.centerText(Memory.TYPE.NAMES[region.type] + " (" + (((region.cBlocks * this.bus.blockSize) / 1024) | 0) + "Kb)"); this.centerText(Memory.TYPE.NAMES[region.type] + " (" + (((region.cBlocks * this.bus.nBlockSize) / 1024) | 0) + "Kb)");
} }
} }
if (DEBUG) this.log("end scanMemory(): total bytes: " + this.busInfo.cbTotal + ", total blocks: " + this.busInfo.cBlocks + ", total regions: " + this.busInfo.cRegions); if (DEBUG) this.log("end scanMemory(): total bytes: " + this.busInfo.cbTotal + ", total blocks: " + this.busInfo.cBlocks + ", total regions: " + this.busInfo.cRegions);
@ -628,7 +628,7 @@ Panel.prototype.findRegions = function()
} }
typeRegion = typeBlock; typeRegion = typeBlock;
iBlockRegion = iBlock; iBlockRegion = iBlock;
addrRegion = nBlockCurr << this.bus.blockShift; addrRegion = nBlockCurr << this.bus.nBlockShift;
} }
nBlockPrev = nBlockCurr; nBlockPrev = nBlockCurr;
} }

View file

@ -114,6 +114,7 @@ var X86 = {
BASE1623: 0x00ff, BASE1623: 0x00ff,
MASK: 0xff00, MASK: 0xff00,
TYPE: { TYPE: {
OFFSET: 0x5,
MASK: 0x1f00, MASK: 0x1f00,
SEG: 0x1000, SEG: 0x1000,
NONSEG: 0x0f00, NONSEG: 0x0f00,

View file

@ -166,8 +166,9 @@ function X86CPU(parmsCPU)
* when the Bus is initialized. * when the Bus is initialized.
*/ */
this.aBusBlocks = this.aMemBlocks = []; this.aBusBlocks = this.aMemBlocks = [];
this.busMask = this.memMask = 0; this.nBusMask = this.nMemMask = 0;
this.blockShift = this.blockSize = this.blockLimit = this.blockTotal = this.blockMask = 0; this.nBlockShift = this.nBlockSize = this.nBlockLimit = this.nBlockTotal = this.nBlockMask = 0;
this.blockDummy = null;
if (SAMPLER) { if (SAMPLER) {
/* /*
@ -576,7 +577,7 @@ X86CPU.PREFETCH = {
}; };
/** /**
* initMemory(aMemBlocks, blockShift) * initMemory(aMemBlocks, nBlockShift)
* *
* Notification from Bus.initMemory(), giving us direct access to the entire memory space * Notification from Bus.initMemory(), giving us direct access to the entire memory space
* (aMemBlocks). * (aMemBlocks).
@ -619,9 +620,9 @@ X86CPU.PREFETCH = {
* *
* @this {X86CPU} * @this {X86CPU}
* @param {Array} aMemBlocks * @param {Array} aMemBlocks
* @param {number} blockShift * @param {number} nBlockShift
*/ */
X86CPU.prototype.initMemory = function(aMemBlocks, blockShift) X86CPU.prototype.initMemory = function(aMemBlocks, nBlockShift)
{ {
/* /*
* aBusBlocks preserves the Bus block array for the life of the machine, whereas aMemBlocks * aBusBlocks preserves the Bus block array for the life of the machine, whereas aMemBlocks
@ -630,11 +631,11 @@ X86CPU.prototype.initMemory = function(aMemBlocks, blockShift)
*/ */
this.aBusBlocks = aMemBlocks; this.aBusBlocks = aMemBlocks;
this.aMemBlocks = aMemBlocks; this.aMemBlocks = aMemBlocks;
this.blockShift = blockShift; this.nBlockShift = nBlockShift;
this.blockSize = 1 << this.blockShift; this.nBlockSize = 1 << this.nBlockShift;
this.blockLimit = this.blockSize - 1; this.nBlockLimit = this.nBlockSize - 1;
this.blockTotal = aMemBlocks.length; this.nBlockTotal = aMemBlocks.length;
this.blockMask = this.blockTotal - 1; this.nBlockMask = this.nBlockTotal - 1;
if (PREFETCH) { if (PREFETCH) {
this.nBusCycles = 0; this.nBusCycles = 0;
this.aPrefetch = new Array(X86CPU.PREFETCH.ARRAY); this.aPrefetch = new Array(X86CPU.PREFETCH.ARRAY);
@ -646,17 +647,17 @@ X86CPU.prototype.initMemory = function(aMemBlocks, blockShift)
}; };
/** /**
* setAddressMask(busMask) * setAddressMask(nBusMask)
* *
* Notification from Bus.initMemory() and Bus.setA20(); the latter calls us whenever the physical * Notification from Bus.initMemory() and Bus.setA20(); the latter calls us whenever the physical
* A20 line changes (note that on a 20-bit bus machine, address lines A20 and higher are always zero). * A20 line changes (note that on a 20-bit bus machine, address lines A20 and higher are always zero).
* *
* For 32-bit bus machines (eg, 80386), busMask is never changed after the initial call, because A20 * For 32-bit bus machines (eg, 80386), nBusMask is never changed after the initial call, because A20
* wrap-around is simulated by changing the physical memory map rather than altering the A20 bit in busMask. * wrap-around is simulated by changing the physical memory map rather than altering the A20 bit in nBusMask.
* *
* We maintain memMask separate from busMask, because when paging is enabled on the 80386, the CPU memory * We maintain memMask separate from nBusMask, because when paging is enabled on the 80386, the CPU memory
* functions are now dealing with linear addresses rather than physical addresses, so it would be incorrect * functions are now dealing with linear addresses rather than physical addresses, so it would be incorrect
* to apply busMask to those addresses; memMask must remain 0xffffffff (-1) for the duration. If we change * to apply nBusMask to those addresses; memMask must remain 0xffffffff (-1) for the duration. If we change
* how A20 is simulated on the 80386, then enablePageBlocks() and disablePageBlocks() will need to override * how A20 is simulated on the 80386, then enablePageBlocks() and disablePageBlocks() will need to override
* memMask appropriately. * memMask appropriately.
* *
@ -664,11 +665,11 @@ X86CPU.prototype.initMemory = function(aMemBlocks, blockShift)
* sets of memory access functions for different machines. * sets of memory access functions for different machines.
* *
* @this {X86CPU} * @this {X86CPU}
* @param {number} busMask * @param {number} nBusMask
*/ */
X86CPU.prototype.setAddressMask = function(busMask) X86CPU.prototype.setAddressMask = function(nBusMask)
{ {
this.busMask = this.memMask = busMask; this.nBusMask = this.nMemMask = nBusMask;
}; };
/** /**
@ -695,9 +696,9 @@ X86CPU.prototype.enablePageBlocks = function()
return; return;
} }
if (this.aMemBlocks === this.aBusBlocks) { if (this.aMemBlocks === this.aBusBlocks) {
this.aMemBlocks = new Array(this.blockTotal); this.aMemBlocks = new Array(this.nBlockTotal);
this.blockUnpaged = new Memory(null, 0, 0, Memory.TYPE.UNPAGED, null, this); this.blockUnpaged = new Memory(null, 0, 0, Memory.TYPE.UNPAGED, null, this);
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) { for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
this.aMemBlocks[iBlock] = this.blockUnpaged; this.aMemBlocks[iBlock] = this.blockUnpaged;
} }
} else { } else {
@ -716,11 +717,11 @@ X86CPU.prototype.enablePageBlocks = function()
* the current page will go directly to that block, instead of coming here through the UNPAGED block * the current page will go directly to that block, instead of coming here through the UNPAGED block
* handlers. * handlers.
* *
* Note that since the incoming address (addr) is a linear address, we never need to mask it with busMask, * Note that since the incoming address (addr) is a linear address, we never need to mask it with nBusMask,
* but all the intermediate (PDE, PTE) and final physical addresses we calculate should still be masked. * but all the intermediate (PDE, PTE) and final physical addresses we calculate should still be masked.
* *
* Granted, busMask on a 32-bit bus is generally going to be 0xffffffff (-1), so making might seem like * Granted, nBusMask on a 32-bit bus is generally going to be 0xffffffff (-1), so making might seem like
* a waste of time; however, if we decide to once again rely on busMask for emulating A20 wrap-around * a waste of time; however, if we decide to once again rely on nBusMask for emulating A20 wrap-around
* (instead of changing the physical memory map to alias the 2nd Mb to the 1st Mb), then performing * (instead of changing the physical memory map to alias the 2nd Mb to the 1st Mb), then performing
* consistent masking will be important. * consistent masking will be important.
* *
@ -747,9 +748,9 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
/* /*
* bus.getLong(addrPDE) would be simpler, but setPhysBlock() needs to know blockPDE and offPDE, too. * bus.getLong(addrPDE) would be simpler, but setPhysBlock() needs to know blockPDE and offPDE, too.
* TODO: Since we're immediately shifting addrPDE by blockShift, then we could also skip adding offPDE. * TODO: Since we're immediately shifting addrPDE by nBlockShift, then we could also skip adding offPDE.
*/ */
var blockPDE = this.aBusBlocks[(addrPDE & this.busMask) >>> this.blockShift]; var blockPDE = this.aBusBlocks[(addrPDE & this.nBusMask) >>> this.nBlockShift];
var pde = blockPDE.readLong(offPDE); var pde = blockPDE.readLong(offPDE);
if (!(pde & X86.PTE.PRESENT)) { if (!(pde & X86.PTE.PRESENT)) {
@ -767,9 +768,9 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
/* /*
* bus.getLong(addrPTE) would be simpler, but setPhysBlock() needs to know blockPTE and offPTE, too. * bus.getLong(addrPTE) would be simpler, but setPhysBlock() needs to know blockPTE and offPTE, too.
* TODO: Since we're immediately shifting addrPDE by blockShift, then we could also skip adding offPTE. * TODO: Since we're immediately shifting addrPDE by nBlockShift, then we could also skip adding offPTE.
*/ */
var blockPTE = this.aBusBlocks[(addrPTE & this.busMask) >>> this.blockShift]; var blockPTE = this.aBusBlocks[(addrPTE & this.nBusMask) >>> this.nBlockShift];
var pte = blockPTE.readLong(offPTE); var pte = blockPTE.readLong(offPTE);
if (!(pte & X86.PTE.PRESENT) && !fSuppress) { if (!(pte & X86.PTE.PRESENT) && !fSuppress) {
@ -784,9 +785,9 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
var addrPhys = (pte & X86.PTE.FRAME) + (addr & X86.LADDR.OFFSET); var addrPhys = (pte & X86.PTE.FRAME) + (addr & X86.LADDR.OFFSET);
/* /*
* TODO: Since we're immediately shifting addrPhys by blockShift, we could also skip adding the addr's offset. * TODO: Since we're immediately shifting addrPhys by nBlockShift, we could also skip adding the addr's offset.
*/ */
var blockPhys = this.aBusBlocks[(addrPhys & this.busMask) >>> this.blockShift]; var blockPhys = this.aBusBlocks[(addrPhys & this.nBusMask) >>> this.nBlockShift];
if (fSuppress) return blockPhys; if (fSuppress) return blockPhys;
/* /*
@ -798,7 +799,7 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
var blockPage = new Memory(addrPage, 0, 0, Memory.TYPE.PAGED); var blockPage = new Memory(addrPage, 0, 0, Memory.TYPE.PAGED);
blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE); blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE);
var iBlock = addr >>> this.blockShift; var iBlock = addr >>> this.nBlockShift;
this.aMemBlocks[iBlock] = blockPage; this.aMemBlocks[iBlock] = blockPage;
this.aBlocksPaged.push(iBlock); this.aBlocksPaged.push(iBlock);
return blockPage; return blockPage;
@ -2718,12 +2719,12 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
*/ */
X86CPU.prototype.probeAddr = function(addr) X86CPU.prototype.probeAddr = function(addr)
{ {
var block = this.aMemBlocks[(addr & this.memMask) >>> this.blockShift]; var block = this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift];
if (block.type == Memory.TYPE.UNPAGED) { if (block.type == Memory.TYPE.UNPAGED) {
block = this.mapPageBlock(addr, false, true); block = this.mapPageBlock(addr, false, true);
if (!block) return null; if (!block) return null;
} }
return block.readByteDirect(addr & this.blockLimit, addr); return block.readByteDirect(addr & this.nBlockLimit, addr);
}; };
/** /**
@ -2739,7 +2740,7 @@ X86CPU.prototype.probeAddr = function(addr)
X86CPU.prototype.getByte = function getByte(addr) X86CPU.prototype.getByte = function getByte(addr)
{ {
if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr); if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
return this.aMemBlocks[(addr & this.memMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr); return this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
}; };
/** /**
@ -2754,8 +2755,8 @@ X86CPU.prototype.getByte = function getByte(addr)
*/ */
X86CPU.prototype.getShort = function getShort(addr) X86CPU.prototype.getShort = function getShort(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.memMask) >>> this.blockShift; var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
/* /*
* On the 8088, it takes 4 cycles to read the additional byte REGARDLESS whether the address is odd or even. * 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). * TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -2766,10 +2767,10 @@ X86CPU.prototype.getShort = function getShort(addr)
this.backTrack.btiMemLo = this.bus.readBackTrack(addr); this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1); this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
} }
if (off < this.blockLimit) { if (off < this.nBlockLimit) {
return this.aMemBlocks[iBlock].readShort(off, addr); return this.aMemBlocks[iBlock].readShort(off, addr);
} }
return this.aMemBlocks[iBlock].readByte(off, addr) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readByte(0, addr + 1) << 8); return this.aMemBlocks[iBlock].readByte(off, addr) | (this.aMemBlocks[(iBlock + 1) & this.nBlockMask].readByte(0, addr + 1) << 8);
}; };
/** /**
@ -2784,17 +2785,17 @@ X86CPU.prototype.getShort = function getShort(addr)
*/ */
X86CPU.prototype.getLong = function getLong(addr) X86CPU.prototype.getLong = function getLong(addr)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.memMask) >>> this.blockShift; var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
if (BACKTRACK) { if (BACKTRACK) {
this.backTrack.btiMemLo = this.bus.readBackTrack(addr); this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1); this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
} }
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off, addr); return this.aMemBlocks[iBlock].readLong(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0, addr + 3) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.nBlockMask].readLong(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -2810,7 +2811,7 @@ X86CPU.prototype.getLong = function getLong(addr)
X86CPU.prototype.setByte = function setByte(addr, b) X86CPU.prototype.setByte = function setByte(addr, b)
{ {
if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo); if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.aMemBlocks[(addr & this.memMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff, addr); this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].writeByte(addr & this.nBlockLimit, b & 0xff, addr);
}; };
/** /**
@ -2825,8 +2826,8 @@ X86CPU.prototype.setByte = function setByte(addr, b)
*/ */
X86CPU.prototype.setShort = function setShort(addr, w) X86CPU.prototype.setShort = function setShort(addr, w)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.memMask) >>> this.blockShift; var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
/* /*
* On the 8088, it takes 4 cycles to write the additional byte REGARDLESS whether the address is odd or even. * 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). * TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -2837,12 +2838,12 @@ X86CPU.prototype.setShort = function setShort(addr, w)
this.bus.writeBackTrack(addr, this.backTrack.btiMemLo); this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi); this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
} }
if (off < this.blockLimit) { if (off < this.nBlockLimit) {
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr); this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr); this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff, addr + 1); this.aMemBlocks[iBlock & this.nBlockMask].writeByte(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -2857,15 +2858,15 @@ X86CPU.prototype.setShort = function setShort(addr, w)
*/ */
X86CPU.prototype.setLong = function setLong(addr, l) X86CPU.prototype.setLong = function setLong(addr, l)
{ {
var off = addr & this.blockLimit; var off = addr & this.nBlockLimit;
var iBlock = (addr & this.memMask) >>> this.blockShift; var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
this.nStepCycles -= this.cycleCounts.nWordCyclePenalty; this.nStepCycles -= this.cycleCounts.nWordCyclePenalty;
if (BACKTRACK) { if (BACKTRACK) {
this.bus.writeBackTrack(addr, this.backTrack.btiMemLo); this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi); this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
} }
if (off < this.blockLimit - 2) { if (off < this.nBlockLimit - 2) {
this.aMemBlocks[iBlock].writeLong(off, l, addr); this.aMemBlocks[iBlock].writeLong(off, l, addr);
return; return;
} }
@ -2873,7 +2874,7 @@ X86CPU.prototype.setLong = function setLong(addr, l)
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLong(off, addr); lPrev = this.aMemBlocks[iBlock].readLong(off, addr);
this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~(-1 << nShift)) | (l << nShift), addr); this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~(-1 << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.nBlockMask;
addr += 3; addr += 3;
lPrev = this.aMemBlocks[iBlock].readLong(0, addr); lPrev = this.aMemBlocks[iBlock].readLong(0, addr);
this.aMemBlocks[iBlock].writeLong(0, (lPrev & (-1 << nShift)) | (l >>> (32 - nShift)), addr); this.aMemBlocks[iBlock].writeLong(0, (lPrev & (-1 << nShift)) | (l >>> (32 - nShift)), addr);
@ -3180,10 +3181,10 @@ 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, * 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. * it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled.
* *
* b = this.aMemBlocks[(addr & this.memMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr); * b = this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
* this.nBusCycles += 4; * this.nBusCycles += 4;
* this.cbPrefetchValid = 0; * this.cbPrefetchValid = 0;
* this.addrPrefetchHead = (addr + 1) & this.memMask; * this.addrPrefetchHead = (addr + 1) & this.nMemMask;
* return b; * return b;
*/ */
} }
@ -3257,10 +3258,10 @@ X86CPU.prototype.fillPrefetch = function(n)
{ {
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) { while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
var addr = this.addrPrefetchHead; var addr = this.addrPrefetchHead;
var b = this.aMemBlocks[(addr & this.memMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr); var b = this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
this.aPrefetch[this.iPrefetchHead] = b | (addr << 8); this.aPrefetch[this.iPrefetchHead] = b | (addr << 8);
if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b)); if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.addrPrefetchHead = (addr + 1) & this.memMask; this.addrPrefetchHead = (addr + 1) & this.nMemMask;
this.iPrefetchHead = (this.iPrefetchHead + 1) & X86CPU.PREFETCH.MASK; this.iPrefetchHead = (this.iPrefetchHead + 1) & X86CPU.PREFETCH.MASK;
this.cbPrefetchQueued++; this.cbPrefetchQueued++;
/* /*

View file

@ -35,6 +35,7 @@
if (typeof module !== 'undefined') { if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib"); var str = require("../../shared/lib/strlib");
var Messages = require("./messages"); var Messages = require("./messages");
var Memory = require("./memory");
var X86 = require("./x86"); var X86 = require("./x86");
} }
@ -308,6 +309,7 @@ X86Seg.prototype.checkReadProt = function checkReadProt(off, cb, fSuppress)
* it to an unsigned value using ">>>"; offMax was already converted at segment load time. * it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/ */
if ((off >>> 0) + cb <= this.offMax) { if ((off >>> 0) + cb <= this.offMax) {
this.blockACC.adw[this.iACC] |= this.bitACC;
return (this.base + off)|0; return (this.base + off)|0;
} }
return this.checkReadProtDisallowed(off, cb, fSuppress); return this.checkReadProtDisallowed(off, cb, fSuppress);
@ -329,6 +331,7 @@ X86Seg.prototype.checkReadProtDown = function checkReadProtDown(off, cb, fSuppre
* it to an unsigned value using ">>>"; offMax was already converted at segment load time. * it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/ */
if ((off >>> 0) + cb > this.offMax) { if ((off >>> 0) + cb > this.offMax) {
this.blockACC.adw[this.iACC] |= this.bitACC;
return (this.base + off)|0; return (this.base + off)|0;
} }
return this.checkReadProtDisallowed(off, cb, fSuppress); return this.checkReadProtDisallowed(off, cb, fSuppress);
@ -367,6 +370,7 @@ X86Seg.prototype.checkWriteProt = function checkWriteProt(off, cb, fSuppress)
* it to an unsigned value using ">>>"; offMax was already converted at segment load time. * it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/ */
if ((off >>> 0) + cb <= this.offMax) { if ((off >>> 0) + cb <= this.offMax) {
this.blockACC.adw[this.iACC] |= this.bitACC;
return (this.base + off)|0; return (this.base + off)|0;
} }
return this.checkWriteProtDisallowed(off, cb, fSuppress); return this.checkWriteProtDisallowed(off, cb, fSuppress);
@ -388,6 +392,7 @@ X86Seg.prototype.checkWriteProtDown = function checkWriteProtDown(off, cb, fSupp
* it to an unsigned value using ">>>"; offMax was already converted at segment load time. * it to an unsigned value using ">>>"; offMax was already converted at segment load time.
*/ */
if ((off >>> 0) + cb > this.offMax) { if ((off >>> 0) + cb > this.offMax) {
this.blockACC.adw[this.iACC] |= this.bitACC;
return (this.base + off)|0; return (this.base + off)|0;
} }
return this.checkWriteProtDisallowed(off, cb, fSuppress); return this.checkWriteProtDisallowed(off, cb, fSuppress);
@ -946,6 +951,46 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
this.fExpDown = true; this.fExpDown = true;
} }
} }
/*
* Here begins the four-step process of computing the block, index and bit mask required
* to update the descriptor's ACCESSED bit whenever the segment is accessed.
*
* Step 1: Compute address of the descriptor byte containing the ACCESSED bit (offset 0x5);
* note that it's perfectly normal for addrDesc to occasionally be invalid (eg, when the CPU
* is creating protected-mode-only segment registers like LDT and TSS, or when the CPU has
* transitioned from real-mode to protected-mode and new selector(s) have not been loaded yet).
*/
this.iACC = this.bitACC = 0;
if (this.addrDesc != X86.ADDR_INVALID) {
var addrAcc = this.addrDesc + X86.DESC.ACC.TYPE.OFFSET;
/*
* Step 2: Compute the logical block number containing that byte, and record the block.
*/
this.blockACC = this.cpu.aMemBlocks[(addrAcc & this.cpu.nMemMask) >>> this.cpu.nBlockShift];
this.cpu.assert(this.blockACC && this.blockACC.adw);
/*
* It's critical that we check fReadOnly, because ROMs often use GDTs that are also located
* in ROM, in which case the ACCESSED bit cannot be set (ie, we must ensure that blockACC is
* set to a dummy block).
*/
if (this.blockACC && !this.blockACC.fReadOnly && this.blockACC.adw) {
/*
* Step 3: Compute the index of the DWORD (adw entry) containing that byte.
*/
this.iACC = (addrAcc & this.cpu.nBlockLimit) >> 2;
/*
* Step 4: Compute the bit that must be OR'ed into that DWORD in order to set the ACCESSED bit;
* we right-shift the bit into byte 0, and then left-shift it into byte 0, 1, 2 or 3 as appropriate.
*/
this.bitACC = Memory.adjustEndian((X86.DESC.ACC.TYPE.ACCESSED >> 8) << ((addrAcc & 0x3) << 3));
}
}
if (!this.bitACC) {
if (!this.cpu.blockDummy) this.cpu.blockDummy = new Memory(0, 0, 4);
this.blockACC = this.cpu.blockDummy;
}
if (fLoad) { if (fLoad) {
/* /*
* Any update to the following properties must occur only on segment loads, not simply when * Any update to the following properties must occur only on segment loads, not simply when