Update ACCESSED bits in GDT/LDT descriptors (finally)
This commit is contained in:
parent
a9b3eb764e
commit
5eed275008
7 changed files with 229 additions and 182 deletions
|
|
@ -85,13 +85,13 @@ function Bus(parmsBus, cpu, dbg)
|
|||
*
|
||||
* 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
|
||||
* nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and
|
||||
* 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.
|
||||
* 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)
|
||||
* ------------ ----------------------------------------------------
|
||||
* this.busLimit 0xfffff
|
||||
* this.busMask [same as busLimit]
|
||||
* this.blockSize 4096
|
||||
* this.blockLen (this.blockSize >> 2)
|
||||
* this.blockShift 12
|
||||
* this.blockLimit 0xfff
|
||||
* this.blockTotal ((this.busLimit + this.blockSize) / this.blockSize) | 0
|
||||
* this.blockMask (this.blockTotal - 1) [ie, 0xff]
|
||||
* this.nBusLimit 0xfffff
|
||||
* this.nBusMask [same as busLimit]
|
||||
* this.nBlockSize 4096
|
||||
* this.nBlockLen (this.nBlockSize >> 2)
|
||||
* this.nBlockShift 12
|
||||
* this.nBlockLimit 0xfff
|
||||
* this.nBlockTotal ((this.nBusLimit + this.nBlockSize) / this.nBlockSize) | 0
|
||||
* 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
|
||||
* --------- ----------- ----------
|
||||
|
|
@ -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
|
||||
* 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).
|
||||
* 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.
|
||||
*/
|
||||
this.addrTotal = Math.pow(2, this.nBusWidth);
|
||||
this.busLimit = this.busMask = (this.addrTotal - 1) | 0;
|
||||
this.blockShift = (PAGEBLOCKS && this.nBusWidth == 32 || 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.addrTotal / this.blockSize) | 0;
|
||||
this.blockMask = this.blockTotal - 1;
|
||||
this.assert(this.blockMask <= Bus.BlockInfo.num.mask);
|
||||
this.nBusLimit = this.nBusMask = (this.addrTotal - 1) | 0;
|
||||
this.nBlockShift = (PAGEBLOCKS && this.nBusWidth == 32 || this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15);
|
||||
this.nBlockSize = 1 << this.nBlockShift;
|
||||
this.nBlockLen = this.nBlockSize >> 2;
|
||||
this.nBlockLimit = this.nBlockSize - 1;
|
||||
this.nBlockTotal = (this.addrTotal / this.nBlockSize) | 0;
|
||||
this.nBlockMask = this.nBlockTotal - 1;
|
||||
this.assert(this.nBlockMask <= Bus.BlockInfo.num.mask);
|
||||
|
||||
/*
|
||||
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
|
||||
|
|
@ -288,12 +288,12 @@ var BusInfo;
|
|||
Bus.prototype.initMemory = function()
|
||||
{
|
||||
var block = new Memory();
|
||||
this.aMemBlocks = new Array(this.blockTotal);
|
||||
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) {
|
||||
this.aMemBlocks = new Array(this.nBlockTotal);
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
this.aMemBlocks[iBlock] = block;
|
||||
}
|
||||
this.cpu.initMemory(this.aMemBlocks, this.blockShift);
|
||||
this.cpu.setAddressMask(this.busMask);
|
||||
this.cpu.initMemory(this.aMemBlocks, this.nBlockShift);
|
||||
this.cpu.setAddressMask(this.nBusMask);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -363,11 +363,11 @@ Bus.prototype.powerUp = function(data, fRepower)
|
|||
*/
|
||||
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) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var addrBlock = iBlock * this.blockSize;
|
||||
var sizeBlock = size > this.blockSize? this.blockSize : size;
|
||||
var addrBlock = iBlock * this.nBlockSize;
|
||||
var sizeBlock = size > this.nBlockSize? this.nBlockSize : size;
|
||||
|
||||
if (block && block.size) {
|
||||
if (block.type == type && block.controller == controller) {
|
||||
|
|
@ -388,18 +388,18 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
|
|||
if (sizeAvail > size) sizeAvail = size;
|
||||
block.used = addr - block.addr + sizeAvail;
|
||||
size -= sizeAvail;
|
||||
addr = addrBlock + this.blockSize;
|
||||
addr = addrBlock + this.nBlockSize;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
block.setDebugger(this.dbg, addr, this.blockSize);
|
||||
block.setDebugger(this.dbg, addr, this.nBlockSize);
|
||||
}
|
||||
size -= sizeBlock;
|
||||
addr = addrBlock + this.blockSize;
|
||||
addr = addrBlock + this.nBlockSize;
|
||||
}
|
||||
if (size > 0) {
|
||||
return this.reportError(2, addr, size);
|
||||
|
|
@ -418,13 +418,13 @@ 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.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
if (this.aMemBlocks[iBlock].fDirty) {
|
||||
this.aMemBlocks[iBlock].fDirty = fClean = false;
|
||||
this.aMemBlocks[iBlock].fDirtyEver = true;
|
||||
}
|
||||
size -= this.blockSize;
|
||||
size -= this.nBlockSize;
|
||||
iBlock++;
|
||||
}
|
||||
return fClean;
|
||||
|
|
@ -447,8 +447,8 @@ Bus.prototype.scanMemory = function(info, addr, size)
|
|||
if (size == null) size = (this.addrTotal - addr) | 0;
|
||||
if (info == null) info = {cbTotal: 0, cBlocks: 0, aBlocks: []};
|
||||
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
var iBlockMax = ((addr + size - 1) >>> this.blockShift);
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
var iBlockMax = ((addr + size - 1) >>> this.nBlockShift);
|
||||
|
||||
info.cbTotal = 0;
|
||||
info.cBlocks = 0;
|
||||
|
|
@ -473,7 +473,7 @@ Bus.prototype.scanMemory = function(info, addr, size)
|
|||
*/
|
||||
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) {
|
||||
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0);
|
||||
if (addrMask != this.busMask) {
|
||||
this.busMask = addrMask;
|
||||
var addrMask = (this.nBusMask & ~0x100000) | (fEnable? 0x100000 : 0);
|
||||
if (addrMask != this.nBusMask) {
|
||||
this.nBusMask = addrMask;
|
||||
if (this.cpu) this.cpu.setAddressMask(addrMask);
|
||||
}
|
||||
}
|
||||
|
|
@ -544,15 +544,15 @@ Bus.prototype.getWidth = function()
|
|||
*/
|
||||
Bus.prototype.setMemoryAccess = function(addr, size, afn)
|
||||
{
|
||||
if (!(addr & this.blockLimit) && size && !(size & this.blockLimit)) {
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
if (!block.controller) {
|
||||
return this.reportError(5, addr, size);
|
||||
}
|
||||
block.setAccess(afn);
|
||||
size -= this.blockSize;
|
||||
size -= this.nBlockSize;
|
||||
iBlock++;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -574,15 +574,15 @@ 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;
|
||||
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
addr = iBlock * this.blockSize;
|
||||
addr = iBlock * this.nBlockSize;
|
||||
var block = this.aMemBlocks[iBlock++] = new Memory(addr);
|
||||
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;
|
||||
}
|
||||
|
|
@ -600,10 +600,10 @@ Bus.prototype.removeMemory = function(addr, size)
|
|||
Bus.prototype.getMemoryBlocks = function(addr, size)
|
||||
{
|
||||
var aBlocks = [];
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
aBlocks.push(this.aMemBlocks[iBlock++]);
|
||||
size -= this.blockSize;
|
||||
size -= this.nBlockSize;
|
||||
}
|
||||
return aBlocks;
|
||||
};
|
||||
|
|
@ -626,7 +626,7 @@ Bus.prototype.getMemoryBlocks = function(addr, size)
|
|||
Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
||||
{
|
||||
var i = 0;
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
var block = aBlocks[i++];
|
||||
this.assert(block);
|
||||
|
|
@ -634,13 +634,13 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
if (type !== undefined) {
|
||||
var blockNew = new Memory(addr);
|
||||
if (DEBUGGER && this.dbg) {
|
||||
blockNew.setDebugger(this.dbg, addr, this.blockSize);
|
||||
blockNew.setDebugger(this.dbg, addr, this.nBlockSize);
|
||||
}
|
||||
blockNew.clone(block, type);
|
||||
block = blockNew;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off != this.blockLimit) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off != this.nBlockLimit) {
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off != this.blockLimit) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off != this.nBlockLimit) {
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off < this.blockLimit - 2) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off < this.nBlockLimit - 2) {
|
||||
return this.aMemBlocks[iBlock].readLong(off, addr);
|
||||
}
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off < this.blockLimit - 2) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off < this.nBlockLimit - 2) {
|
||||
return this.aMemBlocks[iBlock].readLongDirect(off, addr);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off != this.blockLimit) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off != this.nBlockLimit) {
|
||||
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off != this.blockLimit) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off != this.nBlockLimit) {
|
||||
this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff, addr);
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off < this.blockLimit - 2) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off < this.nBlockLimit - 2) {
|
||||
this.aMemBlocks[iBlock].writeLong(off, l);
|
||||
return;
|
||||
}
|
||||
|
|
@ -843,7 +843,7 @@ Bus.prototype.setLong = function(addr, l)
|
|||
off &= ~0x3;
|
||||
lPrev = this.aMemBlocks[iBlock].readLong(off, 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;
|
||||
lPrev = this.aMemBlocks[iBlock].readLong(0, 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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
if (off < this.blockLimit - 2) {
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
if (off < this.nBlockLimit - 2) {
|
||||
this.aMemBlocks[iBlock].writeLongDirect(off, l, addr);
|
||||
return;
|
||||
}
|
||||
|
|
@ -871,7 +871,7 @@ Bus.prototype.setLongDirect = function(addr, l)
|
|||
off &= ~0x3;
|
||||
lPrev = this.aMemBlocks[iBlock].readLongDirect(off, 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;
|
||||
lPrev = this.aMemBlocks[iBlock].readLongDirect(0, 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)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
|
@ -999,8 +999,8 @@ Bus.prototype.writeBackTrack = function(addr, bti)
|
|||
{
|
||||
if (BACKTRACK) {
|
||||
var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT;
|
||||
var iBlock = (addr & this.busMask) >>> this.blockShift;
|
||||
var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.blockLimit, bti);
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.nBlockLimit, bti);
|
||||
var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
|
||||
if (slot != slotPrev) {
|
||||
this.aMemBlocks[iBlock].modBackTrack(true);
|
||||
|
|
@ -1101,7 +1101,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.nBusMask) >>> this.nBlockShift].writeBackTrack(addr & this.nBlockLimit, bti);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1204,7 +1204,7 @@ Bus.prototype.saveMemory = function()
|
|||
{
|
||||
var i = 0;
|
||||
var a = [];
|
||||
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) {
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
/*
|
||||
* 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) {
|
||||
var iBlock = a[i];
|
||||
var adw = a[i+1];
|
||||
if (adw && adw.length < this.blockLen) {
|
||||
adw = State.decompress(adw, this.blockLen);
|
||||
if (adw && adw.length < this.nBlockLen) {
|
||||
adw = State.decompress(adw, this.nBlockLen);
|
||||
}
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
if (!block || !block.restore(adw)) {
|
||||
|
|
@ -1271,8 +1271,8 @@ Bus.prototype.restoreMemory = function(a)
|
|||
Bus.prototype.addMemBreak = function(addr, fWrite)
|
||||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
this.aMemBlocks[iBlock].addBreakpoint(addr & this.blockLimit, fWrite);
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1286,8 +1286,8 @@ Bus.prototype.addMemBreak = function(addr, fWrite)
|
|||
Bus.prototype.removeMemBreak = function(addr, fWrite)
|
||||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.blockLimit, fWrite);
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
0x05: [Debugger.INS.LOADALL,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],
|
||||
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],
|
||||
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_REG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
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],
|
||||
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");
|
||||
|
||||
this.cchAddr = bus.getWidth() >> 2;
|
||||
this.maskAddr = bus.busLimit;
|
||||
this.maskAddr = bus.nBusLimit;
|
||||
|
||||
this.aaOpDescs = Debugger.aaOpDescs;
|
||||
if (this.cpu.model >= X86.MODEL_80186) {
|
||||
|
|
@ -1790,7 +1790,7 @@ if (DEBUGGER) {
|
|||
for (var i = 0; i < this.cpu.aMemBlocks.length; i++) {
|
||||
var block = this.cpu.aBusBlocks[i];
|
||||
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,
|
||||
* 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 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.
|
||||
*
|
||||
* @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
|
||||
* to the A20 line.
|
||||
*/
|
||||
if ((dbgAddr.addr & ~0xffff) == (this.bus.busLimit & ~0xffff)) {
|
||||
if ((dbgAddr.addr & ~0xffff) == (this.bus.nBusLimit & ~0xffff)) {
|
||||
dbgAddr.addr &= 0x000fffff;
|
||||
}
|
||||
symbol['p'] = dbgAddr.addr;
|
||||
|
|
@ -5209,7 +5209,7 @@ if (DEBUGGER) {
|
|||
if (dbgAddr.off == null) return;
|
||||
|
||||
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;
|
||||
if (sAddrEnd !== undefined) {
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ var littleEndian = (TYPEDARRAYS? (function() {
|
|||
* 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,
|
||||
* the size of any given Memory object's underlying buffer can be either zero or bus.blockSize;
|
||||
* 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.nBlockSize;
|
||||
* 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
|
||||
|
|
@ -239,6 +239,19 @@ Memory.TYPE = {
|
|||
*/
|
||||
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 = {
|
||||
constructor: Memory,
|
||||
parent: null,
|
||||
|
|
@ -467,19 +480,6 @@ Memory.prototype = {
|
|||
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)
|
||||
*
|
||||
|
|
@ -513,8 +513,8 @@ Memory.prototype = {
|
|||
this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index)
|
||||
this.blockPTE = blockPTE;
|
||||
this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index)
|
||||
this.bitPTEDirty = this.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY);
|
||||
this.bitPTEAccessed = this.adjustEndian(X86.PTE.ACCESSED);
|
||||
this.bitPTEDirty = Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY);
|
||||
this.bitPTEAccessed = Memory.adjustEndian(X86.PTE.ACCESSED);
|
||||
},
|
||||
/**
|
||||
* addBreakpoint(off, fWrite)
|
||||
|
|
|
|||
|
|
@ -487,8 +487,8 @@ Panel.prototype.findAddress = function(x, y)
|
|||
y -= rect.y;
|
||||
var region = this.busInfo.aRegions[i];
|
||||
var iBlock = usr.getBitField(Bus.BlockInfo.num, this.busInfo.aBlocks[region.iBlock]);
|
||||
var addr = iBlock * this.bus.blockSize;
|
||||
var addrLimit = (iBlock + region.cBlocks) * this.bus.blockSize - 1;
|
||||
var addr = iBlock * this.bus.nBlockSize;
|
||||
var addrLimit = (iBlock + region.cBlocks) * this.bus.nBlockSize - 1;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
* information has changed since the last call.
|
||||
|
|
@ -568,7 +568,7 @@ Panel.prototype.updateAnimation = function()
|
|||
rect = this.busInfo.aRects[i];
|
||||
rect.drawWith(this.contextLiveMem, Memory.TYPE.COLORS[region.type]);
|
||||
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);
|
||||
|
|
@ -628,7 +628,7 @@ Panel.prototype.findRegions = function()
|
|||
}
|
||||
typeRegion = typeBlock;
|
||||
iBlockRegion = iBlock;
|
||||
addrRegion = nBlockCurr << this.bus.blockShift;
|
||||
addrRegion = nBlockCurr << this.bus.nBlockShift;
|
||||
}
|
||||
nBlockPrev = nBlockCurr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ var X86 = {
|
|||
BASE1623: 0x00ff,
|
||||
MASK: 0xff00,
|
||||
TYPE: {
|
||||
OFFSET: 0x5,
|
||||
MASK: 0x1f00,
|
||||
SEG: 0x1000,
|
||||
NONSEG: 0x0f00,
|
||||
|
|
|
|||
|
|
@ -166,8 +166,9 @@ function X86CPU(parmsCPU)
|
|||
* when the Bus is initialized.
|
||||
*/
|
||||
this.aBusBlocks = this.aMemBlocks = [];
|
||||
this.busMask = this.memMask = 0;
|
||||
this.blockShift = this.blockSize = this.blockLimit = this.blockTotal = this.blockMask = 0;
|
||||
this.nBusMask = this.nMemMask = 0;
|
||||
this.nBlockShift = this.nBlockSize = this.nBlockLimit = this.nBlockTotal = this.nBlockMask = 0;
|
||||
this.blockDummy = null;
|
||||
|
||||
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
|
||||
* (aMemBlocks).
|
||||
|
|
@ -619,9 +620,9 @@ X86CPU.PREFETCH = {
|
|||
*
|
||||
* @this {X86CPU}
|
||||
* @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
|
||||
|
|
@ -630,11 +631,11 @@ X86CPU.prototype.initMemory = function(aMemBlocks, blockShift)
|
|||
*/
|
||||
this.aBusBlocks = aMemBlocks;
|
||||
this.aMemBlocks = aMemBlocks;
|
||||
this.blockShift = blockShift;
|
||||
this.blockSize = 1 << this.blockShift;
|
||||
this.blockLimit = this.blockSize - 1;
|
||||
this.blockTotal = aMemBlocks.length;
|
||||
this.blockMask = this.blockTotal - 1;
|
||||
this.nBlockShift = nBlockShift;
|
||||
this.nBlockSize = 1 << this.nBlockShift;
|
||||
this.nBlockLimit = this.nBlockSize - 1;
|
||||
this.nBlockTotal = aMemBlocks.length;
|
||||
this.nBlockMask = this.nBlockTotal - 1;
|
||||
if (PREFETCH) {
|
||||
this.nBusCycles = 0;
|
||||
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
|
||||
* 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
|
||||
* wrap-around is simulated by changing the physical memory map rather than altering the A20 bit in busMask.
|
||||
* 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 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
|
||||
* 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
|
||||
* memMask appropriately.
|
||||
*
|
||||
|
|
@ -664,11 +665,11 @@ X86CPU.prototype.initMemory = function(aMemBlocks, blockShift)
|
|||
* sets of memory access functions for different machines.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
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);
|
||||
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) {
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
this.aMemBlocks[iBlock] = this.blockUnpaged;
|
||||
}
|
||||
} 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
|
||||
* 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.
|
||||
*
|
||||
* Granted, busMask 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
|
||||
* 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 nBusMask for emulating A20 wrap-around
|
||||
* (instead of changing the physical memory map to alias the 2nd Mb to the 1st Mb), then performing
|
||||
* 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.
|
||||
* 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);
|
||||
|
||||
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.
|
||||
* 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);
|
||||
|
||||
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);
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
|
|
@ -798,7 +799,7 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
|
|||
var blockPage = new Memory(addrPage, 0, 0, Memory.TYPE.PAGED);
|
||||
blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE);
|
||||
|
||||
var iBlock = addr >>> this.blockShift;
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock] = blockPage;
|
||||
this.aBlocksPaged.push(iBlock);
|
||||
return blockPage;
|
||||
|
|
@ -2718,12 +2719,12 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
|
|||
*/
|
||||
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) {
|
||||
block = this.mapPageBlock(addr, false, true);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.memMask) >>> this.blockShift;
|
||||
var off = addr & this.nBlockLimit;
|
||||
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.
|
||||
* 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.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].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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.memMask) >>> this.blockShift;
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.memMask) >>> this.blockShift;
|
||||
var off = addr & this.nBlockLimit;
|
||||
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.
|
||||
* 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 + 1, this.backTrack.btiMemHi);
|
||||
}
|
||||
if (off < this.blockLimit) {
|
||||
if (off < this.nBlockLimit) {
|
||||
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
var off = addr & this.blockLimit;
|
||||
var iBlock = (addr & this.memMask) >>> this.blockShift;
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
|
||||
this.nStepCycles -= this.cycleCounts.nWordCyclePenalty;
|
||||
|
||||
if (BACKTRACK) {
|
||||
this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2873,7 +2874,7 @@ X86CPU.prototype.setLong = function setLong(addr, l)
|
|||
off &= ~0x3;
|
||||
lPrev = this.aMemBlocks[iBlock].readLong(off, addr);
|
||||
this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~(-1 << nShift)) | (l << nShift), addr);
|
||||
iBlock = (iBlock + 1) & this.blockMask;
|
||||
iBlock = (iBlock + 1) & this.nBlockMask;
|
||||
addr += 3;
|
||||
lPrev = this.aMemBlocks[iBlock].readLong(0, 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,
|
||||
* 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.cbPrefetchValid = 0;
|
||||
* this.addrPrefetchHead = (addr + 1) & this.memMask;
|
||||
* this.addrPrefetchHead = (addr + 1) & this.nMemMask;
|
||||
* return b;
|
||||
*/
|
||||
}
|
||||
|
|
@ -3257,10 +3258,10 @@ X86CPU.prototype.fillPrefetch = function(n)
|
|||
{
|
||||
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
|
||||
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);
|
||||
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.cbPrefetchQueued++;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
if (typeof module !== 'undefined') {
|
||||
var str = require("../../shared/lib/strlib");
|
||||
var Messages = require("./messages");
|
||||
var Memory = require("./memory");
|
||||
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.
|
||||
*/
|
||||
if ((off >>> 0) + cb <= this.offMax) {
|
||||
this.blockACC.adw[this.iACC] |= this.bitACC;
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if ((off >>> 0) + cb > this.offMax) {
|
||||
this.blockACC.adw[this.iACC] |= this.bitACC;
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if ((off >>> 0) + cb <= this.offMax) {
|
||||
this.blockACC.adw[this.iACC] |= this.bitACC;
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if ((off >>> 0) + cb > this.offMax) {
|
||||
this.blockACC.adw[this.iACC] |= this.bitACC;
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkWriteProtDisallowed(off, cb, fSuppress);
|
||||
|
|
@ -946,6 +951,46 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
|
|||
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) {
|
||||
/*
|
||||
* Any update to the following properties must occur only on segment loads, not simply when
|
||||
|
|
|
|||
Loading…
Reference in a new issue