The PDP-11 Bus component now maintains separate memory maps: one fixed for all Bus (direct) accesses, and another that can vary based on current MMU settings
This commit is contained in:
parent
375146f6bb
commit
a5a40ebab4
4 changed files with 562 additions and 585 deletions
|
|
@ -75,14 +75,6 @@ function BusPDP11(parmsBus, cpu, dbg)
|
|||
*/
|
||||
this.nBusWidth = parmsBus['busWidth'] || 16;
|
||||
|
||||
/*
|
||||
* This controls the location of the IOPAGE (ie, at the top of 16-bit, 18-bit, or 22-bit address range).
|
||||
* It is managed by setIOPageRange(). reset() establishes the default (16).
|
||||
*/
|
||||
this.nIOPageRange = 0; // zero means no IOPAGE access (yet)
|
||||
this.aIOPrevBlocks = []; // this saves any previous blocks we had to replace with IOPAGE blocks
|
||||
this.aIOPageBlocks = null; // this saves the memory blocks allocated for IOPAGE, so we can reuse them
|
||||
|
||||
/*
|
||||
* Compute all BusPDP11 memory block parameters now, based on the width of the bus.
|
||||
*
|
||||
|
|
@ -103,9 +95,6 @@ function BusPDP11(parmsBus, cpu, dbg)
|
|||
this.nBlockMask = this.nBlockTotal - 1;
|
||||
this.assert(this.nBlockMask <= BusPDP11.BlockInfo.num.mask);
|
||||
|
||||
this.iBlockIOPageDefault = ((this.addrTotal - BusPDP11.IOPAGE_LENGTH) & this.nBusMask) >>> this.nBlockShift;
|
||||
this.iBlockIOPageActive = this.iBlockIOPageDefault;
|
||||
|
||||
/*
|
||||
* aIOHandlers is an array (ie, a hash) of I/O notification handlers, indexed by address, where each
|
||||
* entry contains an array:
|
||||
|
|
@ -460,16 +449,34 @@ BusPDP11.IOController = {
|
|||
*
|
||||
* Allocate enough (empty) Memory blocks to span the entire physical address space.
|
||||
*
|
||||
* Note that we now maintain two parallel arrays of these Memory blocks: aBusBlocks is for use by
|
||||
* devices (or any component using the "direct" interfaces), while aMemBlocks is for use by the CPU.
|
||||
*
|
||||
* Whereas the Bus memory map is fixed at init time, the CPU's memory map will vary depending on MMU
|
||||
* settings. The CPU will call setIOPageRange() as needed to update the range of addressible memory,
|
||||
* which in turn will determine where the IOPAGE can be accessed.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
*/
|
||||
BusPDP11.prototype.initMemory = function()
|
||||
{
|
||||
var block = new MemoryPDP11(this);
|
||||
block.copyBreakpoints(this.dbg);
|
||||
|
||||
this.aBusBlocks = new Array(this.nBlockTotal);
|
||||
this.aMemBlocks = new Array(this.nBlockTotal);
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
this.aMemBlocks[iBlock] = block;
|
||||
this.aBusBlocks[iBlock] = this.aMemBlocks[iBlock] = block;
|
||||
}
|
||||
|
||||
var addrIOPage = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
|
||||
this.addMemory(addrIOPage, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
|
||||
|
||||
this.iBlockIOPageBus = (addrIOPage & this.nBusMask) >>> this.nBlockShift;
|
||||
this.iBlockIOPageMem = this.iBlockIOPageBus;
|
||||
|
||||
this.nIOPageRange = 0;
|
||||
this.nMemMask = this.nBusMask;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -478,35 +485,24 @@ BusPDP11.prototype.initMemory = function()
|
|||
* We can define the IOPAGE address range with a single number, because the size of the IOPAGE is fixed at 8Kb.
|
||||
* The bottom of the range is (2 ^ nRange) - IOPAGE_LENGTH, and the top is (2 ^ nRange) - 1.
|
||||
*
|
||||
* Note that we defer our initial call to this function as long as possible (ie, at the end of reset()) so that
|
||||
* other components have first shot at adding their own memory blocks (if any), because addMemory() only allows
|
||||
* installing memory on top of empty memory blocks.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {number} nRange (16, 18 or 22; 0 removes the IOPAGE altogether)
|
||||
*/
|
||||
BusPDP11.prototype.setIOPageRange = function(nRange)
|
||||
{
|
||||
if (nRange != this.nIOPageRange) {
|
||||
var addr;
|
||||
if (this.nIOPageRange) {
|
||||
addr = (1 << this.nIOPageRange) - BusPDP11.IOPAGE_LENGTH;
|
||||
this.setMemoryBlocks(addr, BusPDP11.IOPAGE_LENGTH, this.aIOPrevBlocks);
|
||||
this.nIOPageRange = 0;
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
this.aMemBlocks[iBlock] = this.aBusBlocks[iBlock];
|
||||
}
|
||||
this.nIOPageRange = 0;
|
||||
this.nMemMask = this.nBusMask;
|
||||
if (nRange) {
|
||||
this.nIOPageRange = nRange;
|
||||
addr = (1 << nRange);
|
||||
this.nBusMask = (addr - 1);
|
||||
var addr = (1 << nRange);
|
||||
this.nMemMask = (addr - 1);
|
||||
addr -= BusPDP11.IOPAGE_LENGTH;
|
||||
this.iBlockIOPageActive = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
this.aIOPrevBlocks = this.getMemoryBlocks(addr, BusPDP11.IOPAGE_LENGTH);
|
||||
if (this.aIOPageBlocks) {
|
||||
this.setMemoryBlocks(addr, BusPDP11.IOPAGE_LENGTH, this.aIOPageBlocks);
|
||||
} else {
|
||||
this.addMemory(addr, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
|
||||
this.aIOPageBlocks = this.getMemoryBlocks(addr, BusPDP11.IOPAGE_LENGTH);
|
||||
}
|
||||
this.iBlockIOPageMem = (addr & this.nMemMask) >>> this.nBlockShift;
|
||||
this.aMemBlocks[this.iBlockIOPageMem] = this.aBusBlocks[this.iBlockIOPageBus];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -626,9 +622,9 @@ BusPDP11.prototype.addMemory = function(addr, size, type, controller)
|
|||
var sizeLeft = size;
|
||||
var iBlock = addrNext >>> this.nBlockShift;
|
||||
|
||||
while (sizeLeft > 0 && iBlock < this.aMemBlocks.length) {
|
||||
while (sizeLeft > 0 && iBlock < this.aBusBlocks.length) {
|
||||
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var block = this.aBusBlocks[iBlock];
|
||||
var addrBlock = iBlock * this.nBlockSize;
|
||||
var sizeBlock = this.nBlockSize - (addrNext - addrBlock);
|
||||
if (sizeBlock > sizeLeft) sizeBlock = sizeLeft;
|
||||
|
|
@ -666,7 +662,7 @@ BusPDP11.prototype.addMemory = function(addr, size, type, controller)
|
|||
|
||||
var blockNew = new MemoryPDP11(this, addrNext, sizeBlock, this.nBlockSize, type, controller);
|
||||
blockNew.copyBreakpoints(this.dbg, block);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
this.aBusBlocks[iBlock++] = blockNew;
|
||||
|
||||
addrNext = addrBlock + this.nBlockSize;
|
||||
sizeLeft -= sizeBlock;
|
||||
|
|
@ -695,10 +691,10 @@ BusPDP11.prototype.cleanMemory = function(addr, size)
|
|||
{
|
||||
var fClean = true;
|
||||
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;
|
||||
while (size > 0 && iBlock < this.aBusBlocks.length) {
|
||||
if (this.aBusBlocks[iBlock].fDirty) {
|
||||
this.aBusBlocks[iBlock].fDirty = fClean = false;
|
||||
this.aBusBlocks[iBlock].fDirtyEver = true;
|
||||
}
|
||||
size -= this.nBlockSize;
|
||||
iBlock++;
|
||||
|
|
@ -718,15 +714,8 @@ BusPDP11.prototype.zeroMemory = function(addr, size, pattern)
|
|||
{
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
if (block.controller) {
|
||||
if (this.aIOPageBlocks && this.aIOPageBlocks.length == this.aIOPrevBlocks.length) {
|
||||
var i = this.aIOPageBlocks.indexOf(block);
|
||||
if (i >= 0) block = this.aIOPrevBlocks[i];
|
||||
}
|
||||
}
|
||||
if (block) block.zero(off, size, pattern);
|
||||
while (size > 0 && iBlock < this.aBusBlocks.length) {
|
||||
this.aBusBlocks[iBlock].zero(off, size, pattern);
|
||||
size -= this.nBlockSize;
|
||||
iBlock++;
|
||||
off = 0;
|
||||
|
|
@ -792,7 +781,7 @@ BusPDP11.prototype.scanMemory = function(info, addr, size)
|
|||
info.cbTotal = 0;
|
||||
info.cBlocks = 0;
|
||||
while (iBlock <= iBlockMax) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var block = this.aBusBlocks[iBlock];
|
||||
info.cbTotal += block.size;
|
||||
if (block.size) {
|
||||
info.aBlocks.push(usr.initBitFields(BusPDP11.BlockInfo, iBlock, 0, 0, block.type));
|
||||
|
|
@ -820,10 +809,10 @@ BusPDP11.prototype.removeMemory = function(addr, size)
|
|||
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
var blockOld = this.aMemBlocks[iBlock];
|
||||
var blockOld = this.aBusBlocks[iBlock];
|
||||
var blockNew = new MemoryPDP11(this, addr);
|
||||
blockNew.copyBreakpoints(this.dbg, blockOld);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
this.aBusBlocks[iBlock++] = blockNew;
|
||||
addr = iBlock * this.nBlockSize;
|
||||
size -= this.nBlockSize;
|
||||
}
|
||||
|
|
@ -844,8 +833,8 @@ BusPDP11.prototype.getMemoryBlocks = function(addr, size)
|
|||
{
|
||||
var aBlocks = [];
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
aBlocks.push(this.aMemBlocks[iBlock++]);
|
||||
while (size > 0 && iBlock < this.aBusBlocks.length) {
|
||||
aBlocks.push(this.aBusBlocks[iBlock++]);
|
||||
size -= this.nBlockSize;
|
||||
}
|
||||
return aBlocks;
|
||||
|
|
@ -870,7 +859,7 @@ BusPDP11.prototype.setMemoryAccess = function(addr, size, afn, fQuiet)
|
|||
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var block = this.aBusBlocks[iBlock];
|
||||
if (!block.controller) {
|
||||
return this.reportError(BusPDP11.ERROR.NO_CONTROLLER, addr, size, fQuiet);
|
||||
}
|
||||
|
|
@ -902,7 +891,7 @@ BusPDP11.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
{
|
||||
var i = 0;
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0 && iBlock < this.aMemBlocks.length) {
|
||||
while (size > 0 && iBlock < this.aBusBlocks.length) {
|
||||
var block = aBlocks[i++];
|
||||
this.assert(block);
|
||||
if (!block) break;
|
||||
|
|
@ -911,7 +900,7 @@ BusPDP11.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
blockNew.clone(block, type, this.dbg);
|
||||
block = blockNew;
|
||||
}
|
||||
this.aMemBlocks[iBlock++] = block;
|
||||
this.aBusBlocks[iBlock++] = block;
|
||||
size -= this.nBlockSize;
|
||||
}
|
||||
};
|
||||
|
|
@ -926,30 +915,19 @@ BusPDP11.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
BusPDP11.prototype.getByte = function(addr)
|
||||
{
|
||||
if (addr >= BusPDP11.UNIBUS_22BIT) addr = this.cpu.mapUnibus(addr);
|
||||
return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
|
||||
return this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
|
||||
};
|
||||
|
||||
/**
|
||||
* getBlockDirect(addr)
|
||||
*
|
||||
* This checks for block requests matching the active IOPAGE block and redirects to the original block;
|
||||
* conversely, if the request is for the default IOPAGE block, then the request is redirected to the active
|
||||
* IOPAGE block.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {number} addr is a physical address
|
||||
* @return {MemoryPDP11}
|
||||
*/
|
||||
BusPDP11.prototype.getBlockDirect = function(addr)
|
||||
{
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
if (iBlock == this.iBlockIOPageActive && this.aIOPrevBlocks.length) {
|
||||
block = this.aIOPrevBlocks[0];
|
||||
} else if (iBlock == this.iBlockIOPageDefault) {
|
||||
block = this.aMemBlocks[this.iBlockIOPageActive];
|
||||
}
|
||||
return block;
|
||||
return this.aBusBlocks[(addr & this.nBusMask) >>> this.nBlockShift];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -982,7 +960,7 @@ BusPDP11.prototype.getWord = function(addr)
|
|||
{
|
||||
if (addr >= BusPDP11.UNIBUS_22BIT) addr = this.cpu.mapUnibus(addr);
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
|
||||
if (!PDP11.WORDBUS && off == this.nBlockLimit) {
|
||||
return this.aMemBlocks[iBlock++].readByte(off, addr) | (this.aMemBlocks[iBlock & this.nBlockMask].readByte(0, addr + 1) << 8);
|
||||
}
|
||||
|
|
@ -1025,7 +1003,7 @@ BusPDP11.prototype.getWordDirect = function(addr)
|
|||
BusPDP11.prototype.setByte = function(addr, b)
|
||||
{
|
||||
if (addr >= BusPDP11.UNIBUS_22BIT) addr = this.cpu.mapUnibus(addr);
|
||||
this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeByte(addr & this.nBlockLimit, b & 0xff, addr);
|
||||
this.aMemBlocks[(addr & this.nMemMask) >>> this.nBlockShift].writeByte(addr & this.nBlockLimit, b & 0xff, addr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1058,7 +1036,7 @@ BusPDP11.prototype.setWord = function(addr, w)
|
|||
{
|
||||
if (addr >= BusPDP11.UNIBUS_22BIT) addr = this.cpu.mapUnibus(addr);
|
||||
var off = addr & this.nBlockLimit;
|
||||
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
|
||||
var iBlock = (addr & this.nMemMask) >>> this.nBlockShift;
|
||||
if (!PDP11.WORDBUS && off == this.nBlockLimit) {
|
||||
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr);
|
||||
this.aMemBlocks[iBlock & this.nBlockMask].writeByte(0, (w >> 8) & 0xff, addr + 1);
|
||||
|
|
@ -1104,7 +1082,7 @@ BusPDP11.prototype.addMemBreak = function(addr, fWrite)
|
|||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
this.aBusBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1119,7 +1097,7 @@ BusPDP11.prototype.removeMemBreak = function(addr, fWrite)
|
|||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
this.aBusBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1158,7 +1136,7 @@ BusPDP11.prototype.saveMemory = function(fAll)
|
|||
var a = [];
|
||||
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var block = this.aBusBlocks[iBlock];
|
||||
/*
|
||||
* We have to check both fDirty and fDirtyEver, because we may have called cleanMemory() on some of
|
||||
* the memory blocks (eg, video memory), and while cleanMemory() will clear a dirty block's fDirty flag,
|
||||
|
|
@ -1199,7 +1177,7 @@ BusPDP11.prototype.restoreMemory = function(a)
|
|||
if (adw && adw.length < this.nBlockLen) {
|
||||
adw = State.decompress(adw, this.nBlockLen);
|
||||
}
|
||||
var block = this.aMemBlocks[iBlock];
|
||||
var block = this.aBusBlocks[iBlock];
|
||||
if (!block || !block.restore(adw)) {
|
||||
/*
|
||||
* Either the block to restore hasn't been allocated, indicating a change in the machine
|
||||
|
|
|
|||
|
|
@ -960,7 +960,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
DebuggerPDP11.prototype.dumpBus = function(asArgs)
|
||||
{
|
||||
this.dumpBlocks(this.bus.aMemBlocks, asArgs[0]);
|
||||
this.dumpBlocks(this.bus.aBusBlocks, asArgs[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue