From 5eed275008973d3cc724e36e99aac3bb56d30557 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Mon, 11 May 2015 13:11:30 -0700 Subject: [PATCH] Update ACCESSED bits in GDT/LDT descriptors (finally) --- modules/pcjs/lib/bus.js | 198 +++++++++++++++++------------------ modules/pcjs/lib/debugger.js | 14 +-- modules/pcjs/lib/memory.js | 34 +++--- modules/pcjs/lib/panel.js | 10 +- modules/pcjs/lib/x86.js | 1 + modules/pcjs/lib/x86cpu.js | 109 +++++++++---------- modules/pcjs/lib/x86seg.js | 45 ++++++++ 7 files changed, 229 insertions(+), 182 deletions(-) diff --git a/modules/pcjs/lib/bus.js b/modules/pcjs/lib/bus.js index 1599a7458..58f2ec1e6 100644 --- a/modules/pcjs/lib/bus.js +++ b/modules/pcjs/lib/bus.js @@ -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); } }; diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 43d18b02d..4953f9bd6 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -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) { diff --git a/modules/pcjs/lib/memory.js b/modules/pcjs/lib/memory.js index bc9be95e5..6e1077053 100644 --- a/modules/pcjs/lib/memory.js +++ b/modules/pcjs/lib/memory.js @@ -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) diff --git a/modules/pcjs/lib/panel.js b/modules/pcjs/lib/panel.js index f645648d9..a4fdb9cf2 100644 --- a/modules/pcjs/lib/panel.js +++ b/modules/pcjs/lib/panel.js @@ -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; } diff --git a/modules/pcjs/lib/x86.js b/modules/pcjs/lib/x86.js index 359b4fc34..8582abfa1 100644 --- a/modules/pcjs/lib/x86.js +++ b/modules/pcjs/lib/x86.js @@ -114,6 +114,7 @@ var X86 = { BASE1623: 0x00ff, MASK: 0xff00, TYPE: { + OFFSET: 0x5, MASK: 0x1f00, SEG: 0x1000, NONSEG: 0x0f00, diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index ef563a359..d5da98313 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -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++; /* diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index a1d3e0b85..97bed4a41 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -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