More device refactoring
This commit is contained in:
parent
cd8b6464a3
commit
0ee3a091b4
11 changed files with 1104 additions and 1667 deletions
|
|
@ -116,23 +116,21 @@ function BusPDP11(parmsBus, cpu, dbg)
|
|||
* Memory access handlers must service the entire block; see the setAccess() function in the Memory
|
||||
* component for details.
|
||||
*
|
||||
* Finally, for debugging purposes, if an I/O address has a symbolic name, it will be saved here:
|
||||
*
|
||||
* [4]: symbolic name of I/O address
|
||||
*
|
||||
* UPDATE: The Debugger wants to piggy-back on these arrays to indicate addresses for which it wants
|
||||
* notification. In those cases, the following additional element will be set:
|
||||
*
|
||||
* [4]: true to break on I/O, false to ignore I/O
|
||||
* [5]: true to break on I/O, false to ignore I/O
|
||||
*
|
||||
* The false case is important if fIOBreakAll is set, because it allows the Debugger to selectively
|
||||
* ignore specific addresses.
|
||||
*
|
||||
* Finally, for debugging purposes, if an I/O address has a symbolic name, it will be saved here:
|
||||
*
|
||||
* [5]: symbolic name of I/O address
|
||||
*/
|
||||
this.aIOHandlers = [];
|
||||
this.fIOBreakAll = false;
|
||||
|
||||
this.fnReset = null;
|
||||
this.fnIOAccess = this.unknownIO;
|
||||
this.afnReset = [];
|
||||
|
||||
/*
|
||||
* Allocate empty Memory blocks to span the entire physical address space.
|
||||
|
|
@ -151,7 +149,6 @@ BusPDP11.IOPAGE_22BIT = 0x3FE000; /*017760000*/ // eg, PDP-11/70
|
|||
BusPDP11.IOPAGE_LENGTH = 0x2000; // ie, 8Kb
|
||||
BusPDP11.IOPAGE_MASK = BusPDP11.IOPAGE_LENGTH - 1;
|
||||
BusPDP11.MAX_MEMORY = BusPDP11.IOPAGE_UNIBUS - 16384; // Maximum memory address (need less memory for BSD 2.9 boot)
|
||||
BusPDP11.MAX_ADDRESS = 0x400000; /*020000000*/ // Register addresses are above 22 bit addressing
|
||||
|
||||
BusPDP11.ERROR = {
|
||||
RANGE_INUSE: 1,
|
||||
|
|
@ -191,7 +188,7 @@ BusPDP11.IOController = {
|
|||
var afn = bus.aIOHandlers[off];
|
||||
if (afn) {
|
||||
if (afn[0]) {
|
||||
b = afn[0](addr);
|
||||
b = afn[0](addr) & 0xff; // we mask the result of readByte() in case the caller is re-using their readWord() handler
|
||||
} else if (afn[2]) {
|
||||
if (!(addr & 0x1)) {
|
||||
b = afn[2](addr) & 0xff;
|
||||
|
|
@ -209,13 +206,13 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (b >= 0) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage(afn[5] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true, true);
|
||||
this.dbg.printMessage(afn[4] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true, true);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
b = bus.fnIOAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 1);
|
||||
b = bus.unknownAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 1);
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage("warning: unconverted read access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
|
||||
this.dbg.printMessage("warning: unconverted read access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b), true, true);
|
||||
}
|
||||
return b;
|
||||
},
|
||||
|
|
@ -274,13 +271,13 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (fWrite) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage(afn[5] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true, true);
|
||||
this.dbg.printMessage(afn[4] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
bus.fnIOAccess(addr | BusPDP11.IOPAGE_22BIT, b, 1);
|
||||
bus.unknownAccess(addr | BusPDP11.IOPAGE_22BIT, b, 1);
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage("warning: unconverted write access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
|
||||
this.dbg.printMessage("warning: unconverted write access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b), true, true);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -296,7 +293,6 @@ BusPDP11.IOController = {
|
|||
{
|
||||
var w = -1;
|
||||
var bus = this.controller;
|
||||
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
|
||||
var afn = bus.aIOHandlers[off];
|
||||
if (afn) {
|
||||
if (afn[2]) {
|
||||
|
|
@ -307,13 +303,13 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (w >= 0) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage(afn[5] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true, true);
|
||||
this.dbg.printMessage(afn[4] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true, true);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
w = bus.fnIOAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 0);
|
||||
w = bus.unknownAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 0);
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage("warning: unconverted read access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
|
||||
this.dbg.printMessage("warning: unconverted read access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w), true, true);
|
||||
}
|
||||
return w;
|
||||
},
|
||||
|
|
@ -330,7 +326,6 @@ BusPDP11.IOController = {
|
|||
{
|
||||
var fWrite = false;
|
||||
var bus = this.controller;
|
||||
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
|
||||
var afn = bus.aIOHandlers[off];
|
||||
if (afn) {
|
||||
if (afn[3]) {
|
||||
|
|
@ -344,13 +339,13 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (fWrite) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage(afn[5] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true, true);
|
||||
this.dbg.printMessage(afn[4] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
bus.fnIOAccess(addr | BusPDP11.IOPAGE_22BIT, w, 0);
|
||||
bus.unknownAccess(addr | BusPDP11.IOPAGE_22BIT, w, 0);
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage("warning: unconverted write access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
|
||||
this.dbg.printMessage("warning: unconverted write access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w), true, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -364,7 +359,7 @@ BusPDP11.IOController = {
|
|||
*/
|
||||
BusPDP11.prototype.initMemory = function()
|
||||
{
|
||||
var block = new MemoryPDP11();
|
||||
var block = new MemoryPDP11(this.cpu);
|
||||
block.copyBreakpoints(this.dbg);
|
||||
this.aMemBlocks = new Array(this.nBlockTotal);
|
||||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
|
|
@ -414,18 +409,19 @@ 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.
|
||||
* Call all registered reset() handlers.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
*/
|
||||
BusPDP11.prototype.reset = function()
|
||||
{
|
||||
if (this.fnReset) this.fnReset();
|
||||
for (var i = 0; i < this.afnReset.length; i++) {
|
||||
this.afnReset[i]();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* unknownIO(addr, data, byteFlag)
|
||||
* unknownAccess(addr, data, byteFlag)
|
||||
*
|
||||
* 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
|
||||
|
|
@ -437,12 +433,12 @@ BusPDP11.prototype.reset = function()
|
|||
* @param {number} data (-1 if read, otherwise write)
|
||||
* @param {number} byteFlag (true if byte I/O, otherwise word)
|
||||
*/
|
||||
BusPDP11.prototype.unknownIO = function(addr, data, byteFlag)
|
||||
BusPDP11.prototype.unknownAccess = function(addr, data, byteFlag)
|
||||
{
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
|
||||
this.dbg.printMessage("warning: unrecognized I/O access(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(data) + "," + byteFlag + ")");
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.WARN)) {
|
||||
this.dbg.printMessage("warning: unrecognized I/O access(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(data) + "," + byteFlag + ")", true, true);
|
||||
}
|
||||
return 0;
|
||||
this.cpu.trap(PDP11.TRAP.BUS_ERROR, addr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -537,7 +533,7 @@ BusPDP11.prototype.addMemory = function(addr, size, type, controller)
|
|||
return this.reportError(BusPDP11.ERROR.RANGE_INUSE, addrNext, sizeLeft);
|
||||
}
|
||||
|
||||
var blockNew = new MemoryPDP11(addrNext, sizeBlock, this.nBlockSize, type, controller);
|
||||
var blockNew = new MemoryPDP11(this.cpu, addrNext, sizeBlock, this.nBlockSize, type, controller);
|
||||
blockNew.copyBreakpoints(this.dbg, block);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
|
||||
|
|
@ -675,7 +671,7 @@ BusPDP11.prototype.removeMemory = function(addr, size)
|
|||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
var blockOld = this.aMemBlocks[iBlock];
|
||||
var blockNew = new MemoryPDP11(addr);
|
||||
var blockNew = new MemoryPDP11(this.cpu, addr);
|
||||
blockNew.copyBreakpoints(this.dbg, blockOld);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
addr = iBlock * this.nBlockSize;
|
||||
|
|
@ -761,7 +757,7 @@ BusPDP11.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
this.assert(block);
|
||||
if (!block) break;
|
||||
if (type !== undefined) {
|
||||
var blockNew = new MemoryPDP11(addr);
|
||||
var blockNew = new MemoryPDP11(this.cpu, addr);
|
||||
blockNew.clone(block, type, this.dbg);
|
||||
block = blockNew;
|
||||
}
|
||||
|
|
@ -1044,7 +1040,7 @@ BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte,
|
|||
Component.warning("I/O address already registered: " + str.toHexLong(addr));
|
||||
continue;
|
||||
}
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, false, sName || "unknown"];
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName || "unknown", false];
|
||||
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(addr) + ")");
|
||||
}
|
||||
};
|
||||
|
|
@ -1062,6 +1058,7 @@ BusPDP11.prototype.addIOTable = function(component, table)
|
|||
{
|
||||
for (var port in table) {
|
||||
var afn = table[port];
|
||||
if (afn[5] && afn[5] > this.cpu.model) continue;
|
||||
var fnReadByte = afn[0]? afn[0].bind(component) : null;
|
||||
var fnWriteByte = afn[1]? afn[1].bind(component) : null;
|
||||
var fnReadWord = afn[2]? afn[2].bind(component) : null;
|
||||
|
|
@ -1071,18 +1068,14 @@ BusPDP11.prototype.addIOTable = function(component, table)
|
|||
};
|
||||
|
||||
/**
|
||||
* addIODefaultHandlers(fnReset, fnIOAccess)
|
||||
*
|
||||
* Add default I/O notification handlers.
|
||||
* addResetHandler(fnReset)
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {function()} fnReset
|
||||
* @param {function(number,number,number)} fnIOAccess
|
||||
*/
|
||||
BusPDP11.prototype.addIODefaultHandlers = function(fnReset, fnIOAccess)
|
||||
BusPDP11.prototype.addResetHandler = function(fnReset)
|
||||
{
|
||||
this.fnReset = fnReset;
|
||||
this.fnIOAccess = fnIOAccess;
|
||||
this.afnReset.push(fnReset);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ CPUStatePDP11.prototype.initRegs = function()
|
|||
this.mmuMode = 0; // current memory management mode (see PDP11.MODE.KERNEL | SUPER | UNUSED | USER)
|
||||
this.mmuLastPage = 0;
|
||||
this.mmuLastVirtual = 0;
|
||||
|
||||
this.mapMMR3 = [4,2,0,1]; // map from mode to MMR3 I/D bit
|
||||
this.mmuPDR = [ // memory management PDR registers by mode
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // kernel 0
|
||||
|
|
@ -165,20 +164,14 @@ CPUStatePDP11.prototype.initRegs = function()
|
|||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // mode 2 (not used)
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // user 3
|
||||
];
|
||||
|
||||
this.mmuMap = [ // memory management register by mode - 16 PDR (8 I then 8 D descriptors) followed by 16 PAR (I/D addresses)
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // kernel
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // super
|
||||
[0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // illegal mode 2 requires illegal PDRs
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // user
|
||||
];
|
||||
this.unibusMap = [ // 32 unibus map registers
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
this.controlReg = [ // various control registers we don't really care about
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
this.regsControl = [ // various control registers we don't really care about
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
this.regMB = 0;
|
||||
|
||||
/*
|
||||
* opFlags contains various triggers that stepCPU() needs to be aware of
|
||||
|
|
@ -269,7 +262,6 @@ CPUStatePDP11.prototype.getMMR0 = function()
|
|||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} newMMR0
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.setMMR0 = function(newMMR0)
|
||||
{
|
||||
|
|
@ -286,7 +278,45 @@ CPUStatePDP11.prototype.setMMR0 = function(newMMR0)
|
|||
this.mmuEnable = 0;
|
||||
}
|
||||
this.initMemoryAccess();
|
||||
return this.regMMR0;
|
||||
};
|
||||
|
||||
/**
|
||||
* getMMR1()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getMMR1 = function()
|
||||
{
|
||||
var result = this.regMMR1;
|
||||
if (result & 0xff00) {
|
||||
result = ((result << 8) | (result >> 8)) & 0xffff;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* setMMR3()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} newMMR3
|
||||
*/
|
||||
CPUStatePDP11.prototype.setMMR3 = function(newMMR3)
|
||||
{
|
||||
/*
|
||||
* Don't allow 11/45 to do 22 bit or use unibus map
|
||||
*/
|
||||
if (this.cpuType !== 70) {
|
||||
newMMR3 &= ~(PDP11.MMR3.MMU_22BIT | PDP11.MMR3.UNIBUS_MAP);
|
||||
}
|
||||
this.regMMR3 = newMMR3;
|
||||
if (this.regMMR3 & PDP11.MMR3.MMU_22BIT) {
|
||||
this.mmuMask = 0x3fffff;
|
||||
this.mmuMemorySize = BusPDP11.MAX_MEMORY;
|
||||
} else {
|
||||
this.mmuMask = 0x3ffff;
|
||||
this.mmuMemorySize = BusPDP11.IOPAGE_18BIT;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -772,6 +802,58 @@ CPUStatePDP11.prototype.setPSW = function(newPSW)
|
|||
this.regPSW = newPSW;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSL()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getSL = function()
|
||||
{
|
||||
return this.regSL & 0xff00;
|
||||
};
|
||||
|
||||
/**
|
||||
* setSL(newSL)
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} newSL
|
||||
*/
|
||||
CPUStatePDP11.prototype.setSL = function(newSL)
|
||||
{
|
||||
this.regSL = newSL | 0xff;
|
||||
};
|
||||
|
||||
/**
|
||||
* getPIR()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getPIR = function()
|
||||
{
|
||||
return this.regPIR;
|
||||
};
|
||||
|
||||
/**
|
||||
* setPIR(newPIR)
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} newPIR
|
||||
*/
|
||||
CPUStatePDP11.prototype.setPIR = function(newPIR)
|
||||
{
|
||||
newPIR &= 0xfe00;
|
||||
if (newPIR) {
|
||||
var i = newPIR >> 9;
|
||||
do {
|
||||
newPIR += 0x22;
|
||||
} while (i >>= 1);
|
||||
}
|
||||
this.regPIR = newPIR;
|
||||
this.opFlags |= PDP11.OPFLAG.INTQ;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateNZVFlags(result)
|
||||
*
|
||||
|
|
@ -926,6 +1008,19 @@ CPUStatePDP11.prototype.updateSubFlags = function(result, src, dst)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fault(addr)
|
||||
*
|
||||
* Memory interface for signaling alignment errors.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} addr
|
||||
*/
|
||||
CPUStatePDP11.prototype.fault = function(addr)
|
||||
{
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, addr);
|
||||
};
|
||||
|
||||
/**
|
||||
* panic(reason)
|
||||
*
|
||||
|
|
@ -992,7 +1087,7 @@ CPUStatePDP11.prototype.trap = function(vector, reason)
|
|||
|
||||
if (DEBUG && this.dbg) {
|
||||
if (this.messageEnabled(MessagesPDP11.TRAP)) {
|
||||
this.printMessage("trap to vector " + this.dbg.toStrBase(vector, 0, true) + (reason? " (reason " + reason + ")" : ""), MessagesPDP11.TRAP, true);
|
||||
this.printMessage("trap to vector " + this.dbg.toStrBase(vector, 0, true) + (reason? " (" + this.dbg.toStrBase(reason) + ")" : ""), MessagesPDP11.TRAP, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1057,7 +1152,7 @@ CPUStatePDP11.prototype.mapUnibus = function(unibusAddress)
|
|||
* the operation access mask (accessFlags). If there is no match then the virtual
|
||||
* address is simply mapped as a 16 bit physical address with the upper page going
|
||||
* to the IO address space. Significant access mask values used are PDP11.ACCESS.READ
|
||||
* and PDP11.ACCESS.WRITE
|
||||
* and PDP11.ACCESS.WRITE.
|
||||
*
|
||||
* As an aside it turns out that it is the memory management unit that does odd address
|
||||
* and non-existent memory trapping: who knew? :-) I thought these would have been
|
||||
|
|
@ -1106,11 +1201,6 @@ CPUStatePDP11.prototype.mapVirtualToPhysical = function(virtualAddress, accessFl
|
|||
physicalAddress = ((this.mmuPAR[this.mmuMode][page] << 6) + (virtualAddress & 0x1fff)) & this.mmuMask;
|
||||
|
||||
if (physicalAddress < this.mmuMemorySize) {
|
||||
/*
|
||||
* I'm leaving this code here, per Paul's comments above, but it does surprisingly redundant
|
||||
* to have to perform this check here AND at the physical level (see readWordFromPhysical() and
|
||||
* writeWordToPhysical()).
|
||||
*/
|
||||
if ((physicalAddress & 1) && !(accessFlags & PDP11.ACCESS.BYTE)) {
|
||||
this.regErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.ODDMEMADDR);
|
||||
|
|
@ -1465,10 +1555,6 @@ CPUStatePDP11.prototype.getVirtualAddrByMode = function(mode, reg, accessFlags)
|
|||
*/
|
||||
CPUStatePDP11.prototype.readWordFromPhysical = function(physicalAddress)
|
||||
{
|
||||
if (physicalAddress & 0x1) {
|
||||
this.regErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.ODDMEMADDR);
|
||||
}
|
||||
return this.bus.getWord(physicalAddress);
|
||||
};
|
||||
|
||||
|
|
@ -1483,7 +1569,7 @@ CPUStatePDP11.prototype.readWordFromPhysical = function(physicalAddress)
|
|||
*/
|
||||
CPUStatePDP11.prototype.readWordFromVirtual = function(virtualAddress)
|
||||
{
|
||||
return this.readWordFromPhysical(this.mapVirtualToPhysical(virtualAddress, PDP11.ACCESS.READ_WORD));
|
||||
return this.bus.getWord(this.mapVirtualToPhysical(virtualAddress, PDP11.ACCESS.READ_WORD));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1497,10 +1583,6 @@ CPUStatePDP11.prototype.readWordFromVirtual = function(virtualAddress)
|
|||
*/
|
||||
CPUStatePDP11.prototype.writeWordToPhysical = function(physicalAddress, data)
|
||||
{
|
||||
if (physicalAddress & 0x1) {
|
||||
this.regErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.ODDMEMADDR);
|
||||
}
|
||||
this.bus.setWord(physicalAddress, data & 0xffff);
|
||||
};
|
||||
|
||||
|
|
@ -1515,7 +1597,7 @@ CPUStatePDP11.prototype.writeWordToPhysical = function(physicalAddress, data)
|
|||
*/
|
||||
CPUStatePDP11.prototype.writeWordToVirtual = function(virtualAddress, data)
|
||||
{
|
||||
this.writeWordToPhysical(this.mapVirtualToPhysical(virtualAddress | PDP11.ACCESS.DSPACE, PDP11.ACCESS.WRITE_WORD), data);
|
||||
this.bus.setWord(this.mapVirtualToPhysical(virtualAddress, PDP11.ACCESS.WRITE_WORD), data);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1575,14 +1657,14 @@ CPUStatePDP11.prototype.writeWordToPrevSpace = function(opCode, accessFlags, dat
|
|||
if (!(accessFlags & PDP11.ACCESS.DSPACE)) addr &= 0xffff;
|
||||
/*
|
||||
* TODO: Consider replacing the following code with writeWordToAddr(), by adding optional mmuMode
|
||||
* parameters for each of the discrete mapVirtualToPhysical() and writeWordToPhysical() operations,
|
||||
* because as it stands, this is the only remaining call to mapVirtualToPhysical() outside of our
|
||||
* parameters for each of the discrete mapVirtualToPhysical() and bus.setWord() operations, because
|
||||
* as it stands, this is the only remaining call to mapVirtualToPhysical() outside of our
|
||||
* initMemoryAccess() handlers.
|
||||
*/
|
||||
this.mmuMode = (this.regPSW >> 12) & 3;
|
||||
addr = this.mapVirtualToPhysical(addr | (accessFlags & PDP11.ACCESS.DSPACE), PDP11.ACCESS.WRITE);
|
||||
this.mmuMode = (this.regPSW >> 14) & 3;
|
||||
this.writeWordToPhysical(addr, data);
|
||||
this.bus.setWord(addr, data);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1623,7 +1705,7 @@ CPUStatePDP11.prototype.readSrcWord = function(opCode)
|
|||
if (!mode) {
|
||||
result = this.regsGen[reg];
|
||||
} else {
|
||||
result = this.readWordFromPhysical(this.getAddrByMode(mode, reg, PDP11.ACCESS.READ_WORD));
|
||||
result = this.bus.getWord(this.getAddrByMode(mode, reg, PDP11.ACCESS.READ_WORD));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
@ -1677,7 +1759,7 @@ CPUStatePDP11.prototype.readDstWord = function(opCode)
|
|||
if (!mode) {
|
||||
result = this.regsGen[reg];
|
||||
} else {
|
||||
result = this.readWordFromPhysical(this.getAddrByMode(mode, reg, PDP11.ACCESS.READ_WORD));
|
||||
result = this.bus.getWord(this.getAddrByMode(mode, reg, PDP11.ACCESS.READ_WORD));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
@ -1722,7 +1804,7 @@ CPUStatePDP11.prototype.updateDstWord = function(opCode, src, fnOp)
|
|||
this.regsGen[reg] = fnOp.call(this, src, this.regsGen[reg]);
|
||||
} else {
|
||||
var addr = this.getAddrByMode(mode, reg, PDP11.ACCESS.UPDATE_WORD);
|
||||
this.writeWordToPhysical(addr, fnOp.call(this, src, this.readWordFromPhysical(addr)));
|
||||
this.bus.setWord(addr, fnOp.call(this, src, this.bus.getWord(addr)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1772,7 +1854,7 @@ CPUStatePDP11.prototype.writeDstWord = function(opCode, data)
|
|||
if (!mode) {
|
||||
this.regsGen[reg] = data & 0xffff;
|
||||
} else {
|
||||
this.writeWordToPhysical(this.getAddrByMode(mode, reg, PDP11.ACCESS.WRITE_WORD), data);
|
||||
this.bus.setWord(this.getAddrByMode(mode, reg, PDP11.ACCESS.WRITE_WORD), data);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.nDisableMessages++;
|
||||
/*
|
||||
* TODO: We also need a Bus interface to disable fnIOAccess() calls that could trigger a trap().
|
||||
* TODO: We also need a Bus interface to disable accesses that could trigger a trap().
|
||||
*/
|
||||
b = this.bus.getByteDirect(addr);
|
||||
this.nDisableMessages--;
|
||||
|
|
@ -613,7 +613,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.nDisableMessages++;
|
||||
/*
|
||||
* TODO: We also need a Bus interface to disable fnIOAccess() calls that could trigger a trap().
|
||||
* TODO: We also need a Bus interface to disable accesses that could trigger a trap().
|
||||
*
|
||||
* NOTE: We don't care if the word address is aligned, because 1) we assume the user knows what
|
||||
* they're doing, and 2) the Bus simply ignores the low address bit anyway. Alignment checks are
|
||||
|
|
@ -640,7 +640,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.nDisableMessages++;
|
||||
/*
|
||||
* TODO: We also need a Bus interface to disable fnIOAccess() calls that could trigger a trap().
|
||||
* TODO: We also need a Bus interface to disable accesses that could trigger a trap().
|
||||
*/
|
||||
this.bus.setByteDirect(addr, b);
|
||||
this.nDisableMessages--;
|
||||
|
|
@ -663,7 +663,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.nDisableMessages++;
|
||||
/*
|
||||
* TODO: We also need a Bus interface to disable fnIOAccess() calls that could trigger a trap().
|
||||
* TODO: We also need a Bus interface to disable accesses that could trigger a trap().
|
||||
*
|
||||
* NOTE: We don't care if the word address is aligned, because 1) we assume the user knows what
|
||||
* they're doing, and 2) the Bus simply ignores the low address bit anyway. Alignment checks are
|
||||
|
|
|
|||
|
|
@ -455,11 +455,40 @@ var PDP11 = {
|
|||
UDSAR6: 0o177674, // User D Space Address Register 6
|
||||
UDSAR7: 0o177676, // User D Space Address Register 7
|
||||
|
||||
SIZE_LO: 0o177760, // Lower Size Register (last 32-word block) (11/70 only?)
|
||||
SIZE_HI: 0o177762, // Upper Size Register (always zero) (11/70 only?)
|
||||
SYSID: 0o177764, // System ID Register (11/70 only?)
|
||||
CPUERR: 0o177766, // CPU error (11/70 only?)
|
||||
MB: 0o177770, // Microprogram break (11/70 only?)
|
||||
R0SET0: 0o177700,
|
||||
R1SET0: 0o177701,
|
||||
R2SET0: 0o177702,
|
||||
R3SET0: 0o177703,
|
||||
R4SET0: 0o177704,
|
||||
R5SET0: 0o177705,
|
||||
R6KERNEL: 0o177706,
|
||||
R7KERNEL: 0o177707,
|
||||
R0SET1: 0o177710,
|
||||
R1SET1: 0o177711,
|
||||
R2SET1: 0o177712,
|
||||
R3SET1: 0o177713,
|
||||
R4SET1: 0o177714,
|
||||
R5SET1: 0o177715,
|
||||
R6SUPER: 0o177716,
|
||||
R6USER: 0o177717,
|
||||
|
||||
/*
|
||||
* This next group of registers is largely ignored; all accesses are routed to regsControl[]
|
||||
*/
|
||||
LAERR: 0o177740, // Low Address Error (11/70 only)
|
||||
HAERR: 0o177742, // High Address Error (11/70 only)
|
||||
MEMERR: 0o177744, // Memory System Error (11/70 only)
|
||||
CACHEC: 0o177746, // Cache Control (11/70 only)
|
||||
MAINT: 0o177750, // Maintenance (11/70 only)
|
||||
HITMISS: 0o177752, // Hit/Miss (11/70 only)
|
||||
UNDEF1: 0o177754,
|
||||
UNDEF2: 0o177756,
|
||||
|
||||
LSIZE: 0o177760, // Lower Size Register (last 32-word block) (11/70 only)
|
||||
HSIZE: 0o177762, // Upper Size Register (always zero) (11/70 only)
|
||||
SYSID: 0o177764, // System ID Register (11/70 only)
|
||||
CPUERR: 0o177766, // CPU error (11/70 only)
|
||||
MB: 0o177770, // Microprogram break
|
||||
PIR: 0o177772, // Program Interrupt Request
|
||||
SL: 0o177774, // Stack Limit Register
|
||||
PSW: 0o177776 // 777776 17777776 0x3FFFFE Processor Status Word
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -56,7 +56,7 @@ var littleEndian = (TYPEDARRAYS? (function() {
|
|||
})() : false);
|
||||
|
||||
/**
|
||||
* MemoryPDP11(addr, used, size, type, controller)
|
||||
* MemoryPDP11(cpu, 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.nBlockSize; however,
|
||||
|
|
@ -89,15 +89,17 @@ var littleEndian = (TYPEDARRAYS? (function() {
|
|||
* is available).
|
||||
*
|
||||
* @constructor
|
||||
* @param {CPUStatePDP11} cpu
|
||||
* @param {number|null} [addr] of lowest used address in block
|
||||
* @param {number} [used] portion of block in bytes (0 for none); must be a multiple of 4
|
||||
* @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4
|
||||
* @param {number} [type] is one of the MemoryPDP11.TYPE constants (default is MemoryPDP11.TYPE.NONE)
|
||||
* @param {Object} [controller] is an optional memory controller component
|
||||
*/
|
||||
function MemoryPDP11(addr, used, size, type, controller)
|
||||
function MemoryPDP11(cpu, addr, used, size, type, controller)
|
||||
{
|
||||
var i;
|
||||
this.cpu = cpu;
|
||||
this.id = (MemoryPDP11.idBlock += 2);
|
||||
this.adw = null;
|
||||
this.offset = 0;
|
||||
|
|
@ -621,6 +623,9 @@ MemoryPDP11.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readWordMemory: function readWordMemory(off, addr) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
if (BYTEARRAYS) {
|
||||
return this.ab[off] | (this.ab[off + 1] << 8);
|
||||
}
|
||||
|
|
@ -662,6 +667,9 @@ MemoryPDP11.prototype = {
|
|||
* @param {number} addr
|
||||
*/
|
||||
writeWordMemory: function writeWordMemory(off, w, addr) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
if (BYTEARRAYS) {
|
||||
this.ab[off] = (w & 0xff);
|
||||
this.ab[off + 1] = (w >> 8);
|
||||
|
|
@ -769,6 +777,9 @@ MemoryPDP11.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readWordBE: function readWordBE(off, addr) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
return this.dv.getUint16(off, true);
|
||||
},
|
||||
/**
|
||||
|
|
@ -785,7 +796,10 @@ MemoryPDP11.prototype = {
|
|||
* for an aligned read vs. always reading the bytes separately.
|
||||
*/
|
||||
var w;
|
||||
if (PDP11.WORDBUS || !(off & 0x1)) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
if (!(off & 0x1)) {
|
||||
w = this.aw[off >> 1];
|
||||
} else {
|
||||
w = this.ab[off] | (this.ab[off+1] << 8);
|
||||
|
|
@ -831,6 +845,9 @@ MemoryPDP11.prototype = {
|
|||
* @param {number} w
|
||||
*/
|
||||
writeWordBE: function writeWordBE(off, w, addr) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
this.dv.setUint16(off, w, true);
|
||||
this.fDirty = true;
|
||||
},
|
||||
|
|
@ -847,7 +864,10 @@ MemoryPDP11.prototype = {
|
|||
* TODO: For non-WORDBUS machines, it remains to be seen if there's any advantage to checking the offset
|
||||
* for an aligned write vs. always writing the bytes separately.
|
||||
*/
|
||||
if (PDP11.WORDBUS || !(off & 0x1)) {
|
||||
if (PDP11.WORDBUS && (off & 0x1)) {
|
||||
this.cpu.fault(addr);
|
||||
}
|
||||
if (!(off & 0x1)) {
|
||||
this.aw[off >> 1] = w;
|
||||
} else {
|
||||
this.ab[off] = w;
|
||||
|
|
|
|||
85
modules/pdp11/lib/rk11.js
Normal file
85
modules/pdp11/lib/rk11.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* @fileoverview Implements RK11 device support.
|
||||
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
|
||||
* @copyright Jeff Parsons 2012-2016
|
||||
*
|
||||
* This file is part of PCjs, a computer emulation software project at <http://pcjs.org/>.
|
||||
*
|
||||
* It has been adapted from the JavaScript PDP 11/70 Emulator v1.3 written by Paul Nankervis
|
||||
* (paulnank@hotmail.com) as of August 2016 from http://skn.noip.me/pdp11/pdp11.html. This code
|
||||
* may be used freely provided the original author name is acknowledged in any modified source code.
|
||||
*
|
||||
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCjs. If not,
|
||||
* see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
* You are required to include the above copyright notice in every source code file of every
|
||||
* copy or modified version of this work, and to display that copyright notice on every screen
|
||||
* that loads or runs any version of this software (see COPYRIGHT in /modules/shared/lib/defines.js).
|
||||
*
|
||||
* Some PCjs files also attempt to load external resource files, such as character-image files,
|
||||
* ROM files, and disk image files. Those external resource files are not considered part of PCjs
|
||||
* for purposes of the GNU General Public License, and the author does not claim any copyright
|
||||
* as to their contents.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (NODE) {
|
||||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var State = require("../../shared/lib/state");
|
||||
var BusPDP11 = require("./bus");
|
||||
}
|
||||
|
||||
/**
|
||||
* RK11(parmsDevice)
|
||||
*
|
||||
* @constructor
|
||||
* @extends Component
|
||||
* @param {Object} parmsRK11
|
||||
*/
|
||||
function RK11(parmsRK11)
|
||||
{
|
||||
Component.call(this, "RK11", parmsRK11, RK11);
|
||||
|
||||
this.rkds = 0x9C0;/*04700*/ // 017777400 Drive Status
|
||||
this.rker = 0; // 017777402 Error Register
|
||||
this.rkcs = 0x80; /*0200*/ // 017777404 Control Status
|
||||
this.rkwc = 0; // 017777406 Word Count
|
||||
this.rkba = 0; // 017777410 Bus Address
|
||||
this.rkda = 0; // 017777412 Disk Address
|
||||
this.rkdb = 0; // 017777416 Data Buffer
|
||||
this.meta = [];
|
||||
this.TRACKS = [406, 406, 406, 406];
|
||||
this.SECTORS = [12, 12, 12, 12];
|
||||
}
|
||||
|
||||
Component.subclass(RK11);
|
||||
|
||||
/**
|
||||
* initBus(cmp, bus, cpu, dbg)
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {ComputerPDP11} cmp
|
||||
* @param {BusPDP11} bus
|
||||
* @param {CPUStatePDP11} cpu
|
||||
* @param {DebuggerPDP11} dbg
|
||||
*/
|
||||
RK11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
if (NODE) module.exports = RK11;
|
||||
Loading…
Reference in a new issue