Laid groundwork for MMU-specific functions, to avoid address mapping work when unnecessary

This commit is contained in:
Jeff 2016-09-25 12:12:26 -07:00 committed by Jeff Parsons
commit da617d454d
6 changed files with 804 additions and 687 deletions

View file

@ -171,19 +171,20 @@ BusPDP11.ERROR = {
* array), and since these I/O accesses should be pretty infrequent relative to all other memory accesses,
* the benefit seems pretty minimal.
*/
BusPDP11.controller = {
BusPDP11.IOController = {
/**
* readIOPageByte(off, addr)
* readByte(off, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readIOPageByte: function(off, addr)
readByte: function(off, addr)
{
var afn = this.controller.aIOHandlers[off];
var bus = this.controller;
var afn = bus.aIOHandlers[off];
if (afn) {
if (afn[0]) {
return afn[0](addr);
@ -195,26 +196,27 @@ BusPDP11.controller = {
}
}
} else if (addr & 0x1) {
afn = this.controller.aIOHandlers[off & ~0x1];
afn = bus.aIOHandlers[off & ~0x1];
if (afn[2]) {
return afn[2](addr & ~0x1) >> 8;
}
}
return this.controller.fnAccess(addr, -1, 1);
return bus.fnAccess(addr, -1, 1);
},
/**
* writeIOPageByte(off, b, addr)
* writeByte(off, b, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits)
* @param {number} addr
*/
writeIOPageByte: function(off, b, addr)
writeByte: function(off, b, addr)
{
var w;
var afn = this.controller.aIOHandlers[off];
var bus = this.controller;
var afn = bus.aIOHandlers[off];
if (afn) {
if (afn[1]) {
afn[1](b, addr);
@ -229,7 +231,7 @@ BusPDP11.controller = {
return;
}
} else if (addr & 0x1) {
afn = this.controller.aIOHandlers[off & ~0x1];
afn = bus.aIOHandlers[off & ~0x1];
if (afn[3]) {
addr &= ~0x1;
w = afn[2]? afn[2](addr) : 0;
@ -237,21 +239,22 @@ BusPDP11.controller = {
return;
}
}
this.controller.fnAccess(addr, b, 1);
bus.fnAccess(addr, b, 1);
},
/**
* readIOPageShort(off, addr)
* readShort(off, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readIOPageShort: function(off, addr)
readShort: function(off, addr)
{
var bus = this.controller;
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
var afn = this.controller.aIOHandlers[off];
var afn = bus.aIOHandlers[off];
if (afn) {
if (afn[2]) {
return afn[2](addr);
@ -259,21 +262,22 @@ BusPDP11.controller = {
return afn[0](addr) | (afn[0](addr + 1) << 8);
}
}
return this.controller.fnAccess(addr, -1, 0);
return bus.fnAccess(addr, -1, 0);
},
/**
* writeIOPageShort(off, w, addr)
* writeShort(off, w, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} w (which should already be pre-masked to 16 bits)
* @param {number} addr
*/
writeIOPageShort: function(off, w, addr)
writeShort: function(off, w, addr)
{
var bus = this.controller;
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
var afn = this.controller.aIOHandlers[off];
var afn = bus.aIOHandlers[off];
if (afn) {
if (afn[3]) {
afn[3](w, addr);
@ -284,7 +288,7 @@ BusPDP11.controller = {
return;
}
}
this.controller.fnAccess(addr, w, 0);
bus.fnAccess(addr, w, 0);
}
};
@ -304,12 +308,17 @@ BusPDP11.prototype.initMemory = function()
this.aMemBlocks[iBlock] = block;
}
this.afnIOPage = new Array(4);
this.afnIOPage[0] = BusPDP11.controller.readIOPageByte;
this.afnIOPage[1] = BusPDP11.controller.writeIOPageByte;
this.afnIOPage[2] = BusPDP11.controller.readIOPageShort;
this.afnIOPage[3] = BusPDP11.controller.writeIOPageShort;
this.addrIOPage = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
this.addMemory(this.addrIOPage, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
this.afnIOPage[0] = BusPDP11.IOController.readByte;
this.afnIOPage[1] = BusPDP11.IOController.writeByte;
this.afnIOPage[2] = BusPDP11.IOController.readShort;
this.afnIOPage[3] = BusPDP11.IOController.writeShort;
/*
* Map IOPAGE at the top of the address space (as determined by nBusWidth), as well as at IOPAGE_VIRT
* (which is the only place that 16-bit code can reach the IOPAGE when memory management is not enabled).
*/
var addr = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
this.addMemory(addr, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
this.addMemory(BusPDP11.IOPAGE_VIRT, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
};
/**
@ -342,6 +351,9 @@ BusPDP11.prototype.getControllerAccess = function()
/**
* reset()
*
* The Device component initializes fnReset by calling addIODefaultHandlers() from its initBus() function;
* it will be that function's responsibility to reset all the necessary devices.
*
* @this {BusPDP11}
*/
BusPDP11.prototype.reset = function()
@ -352,10 +364,15 @@ BusPDP11.prototype.reset = function()
/**
* access()
*
* This is our default I/O handler, called whenever there's an IOPAGE access without a corresponding entry
* in aIOHandlers; in the interim, our Device component will override this default handler with its own function
* by calling addIODefaultHandlers(), until the Device component has been completely rewritten to install I/O
* handlers for all supported I/O addresses.
*
* @this {BusPDP11}
* @param {number} addr
* @param {number} data
* @param {number} byteFlag
* @param {number} addr (ie, an IOPAGE address)
* @param {number} data (-1 if read, otherwise write)
* @param {number} byteFlag (true if byte I/O, otherwise word)
*/
BusPDP11.prototype.access = function(addr, data, byteFlag)
{
@ -957,11 +974,11 @@ BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte,
for (var addr = start; addr <= end; addr += 2) {
var off = addr & BusPDP11.IOPAGE_MASK;
if (this.aIOHandlers[off] !== undefined) {
Component.warning("I/O address already registered: " + str.toHexLong(this.addrIOPage + off));
Component.warning("I/O address already registered: " + str.toHexLong(addr));
continue;
}
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadShort, fnWriteShort, false];
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(this.addrIOPage + off) + ")");
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(addr) + ")");
}
};

File diff suppressed because it is too large Load diff

View file

@ -226,7 +226,8 @@ var PDP11 = {
BYTE: 0x1,
READ: 0x2,
WRITE: 0x4,
UPDATE: 0x6
UPDATE: 0x6,
DSPACE: 0x10000 // set bit 17 in any 16-bit virtual address that refers to D space (as opposed to I space)
},
/*
* Internal flags passed to writeByteByMode(), etc.
@ -276,13 +277,17 @@ var PDP11 = {
/*
* Assorted special (UNIBUS) addresses
*
* Within the PDP-11's 18-bit address space, of the 0x40000 possible addresses, the top 8Kb (0x2000)
* is called the IOPAGE and is reserved for CPU and I/O registers. The IOPAGE spans 0x3E000-0x3FFFF.
* Within the PDP-11/45's 18-bit address space, of the 0x40000 possible addresses (256Kb), the top 0x2000
* (8Kb) is called the IOPAGE and is reserved for CPU and I/O registers. The IOPAGE spans 0x3E000-0x3FFFF.
*
* To map UNIBUS addresses to 22-bit physical addresses, a UNIBUS relocation map is used. It consists
* of 31 double-word registers that each hold a 22-bit base address. When UNIBUS relocation is enabled,
* the top 5 bits of an address select one of the 31 mapping registers, and the bottom 13 bits are then
* added to the contents of the selected mapping register.
* Within the PDP-11/70's 22-bit address space, of the 0x400000 possible addresses (4Mb), the top 0x20000
* (256Kb) is mapped to the UNIBUS (not physical memory), and as before, the top 0x2000 (8Kb) of that is
* mapped to the IOPAGE.
*
* To map 18-bit UNIBUS addresses to 22-bit physical addresses, the 11/70 uses a UNIBUS relocation map.
* It consists of 31 double-word registers that each hold a 22-bit base address. When UNIBUS relocation
* is enabled, the top 5 bits of an address select one of the 31 mapping registers, and the bottom 13 bits
* are then added to the contents of the selected mapping register.
*
* ES6 ALERT: By using octal constants, this is the first place I'm dipping my toe into ECMAScript 6 waters.
* If you're loading this raw source code into your browser, then by now (2016) you're almost certainly using
@ -293,11 +298,15 @@ var PDP11 = {
* For more details: https://github.com/google/closure-compiler/wiki/ECMAScript6
*/
UNIBUS: { //16-bit 18-bit 22-bit Hex Description
PSW: 0o177776, // 777776 17777776 0x3FFFFE PSW
SL: 0o177774, // Stack Limit
PSW: 0o177776, // 777776 17777776 0x3FFFFE Processor Status Word
SL: 0o177774, // Stack Limit Register
PIR: 0o177772, // Program Interrupt Request
MB: 0o177770, // Microprogram break
CPUERR: 0o177766, // CPU error
MB: 0o177770, // Microprogram break (11/70 only?)
CPUERR: 0o177766, // CPU error (11/70 only?)
SYSID: 0o177764, // System ID Register (11/70 only?)
SIZE_HI: 0o177762, // Upper Size Register (always zero) (11/70 only?)
SIZE_LO: 0o177760, // Lower Size Register (last 32-word block) (11/70 only?)
DISPLAY: 0o177570, // Console Switch and Display
MMR0: 0o177572, // 777572 17777572
MMR1: 0o177574, // 777574 17777574
MMR2: 0o177576, // 777576 17777576

View file

@ -734,7 +734,7 @@ DevicePDP11.prototype.readData = function(meta, block, address, count)
return;
}
for (word = 0; word < meta.blocksize && count > 0; word++) {
if (this.cpu.writeWordByAddr((meta.mapped? this.cpu.mapUnibus(address) : address), meta.cache[block][word]) < 0) {
if (this.cpu.writeWordByPhysical((meta.mapped? this.cpu.mapUnibus(address) : address), meta.cache[block][word]) < 0) {
meta.postProcess(2, meta, block, address, count); // NXM
return;
}
@ -768,7 +768,7 @@ DevicePDP11.prototype.writeData = function(meta, block, address, count)
}
}
for (word = 0; word < meta.blocksize && count > 0; word++) {
data = this.cpu.readWordByAddr((meta.mapped? this.cpu.mapUnibus(address) : address));
data = this.cpu.readWordByPhysical((meta.mapped? this.cpu.mapUnibus(address) : address));
if (data < 0) {
meta.postProcess(2, meta, block, address, count); // NXM
return;