Laid groundwork for MMU-specific functions, to avoid address mapping work when unnecessary
This commit is contained in:
parent
56c305ca64
commit
da617d454d
6 changed files with 804 additions and 687 deletions
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue