More device refactoring

This commit is contained in:
Jeff Parsons 2016-10-07 17:37:13 -07:00 committed by Jeff Parsons
commit 0ee3a091b4
11 changed files with 1104 additions and 1667 deletions

View file

@ -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);
};
/**

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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
View 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;