Simplified the I/O registration function, added support for Panel debugger messages, and added some new Panel behavior on the RESET instruction

This commit is contained in:
Jeff 2016-11-15 10:05:25 -08:00 committed by Jeff Parsons
commit 5bc0c8cca9
12 changed files with 327 additions and 246 deletions

View file

@ -1272,7 +1272,7 @@ BusPDP11.prototype.getMemorySize = function(type)
};
/**
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName)
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, msgCategory, sName)
*
* Add I/O notification handlers to the master list (aIOHandlers). The start and end addresses are typically
* relative to the starting IOPAGE address, but they can also be absolute; we simply mask all addresses with
@ -1281,7 +1281,9 @@ BusPDP11.prototype.getMemorySize = function(type)
* CAVEATS: If a conflict is reported, a partial set of handlers may still have been added. There is no mechanism
* for removing handlers, since this is considered an initialization function. And finally, when a range of addresses
* is used, each successive address is advanced by 2, so if you really want to add a handler for a "+1" (usually odd)
* address, then you must add it individually.
* address, then you must add it individually. Failure to do is not necessarily fatal, because the IOController's
* fallback behavior for an odd address is to call the byte handler for the preceding even address, but the byte
* handler must be prepared for that (the handlers installed by ROM component's addROM() function are a good example).
*
* @this {BusPDP11}
* @param {number} start address
@ -1309,18 +1311,16 @@ BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte,
};
/**
* addIOTable(component, table, msgCategory, sName)
* addIOTable(component, table)
*
* Add I/O notification handlers from the specified table (a batch version of addIOHandlers).
*
* @this {BusPDP11}
* @param {Component} component
* @param {Object} table
* @param {number} [msgCategory] (default is BUS)
* @param {string} [sName]
* @return {boolean} (true if entire range successfully registered, false if any conflicts)
*/
BusPDP11.prototype.addIOTable = function(component, table, msgCategory, sName)
BusPDP11.prototype.addIOTable = function(component, table)
{
for (var port in table) {
var addr = +port;
@ -1336,7 +1336,6 @@ BusPDP11.prototype.addIOTable = function(component, table, msgCategory, sName)
var fnWriteByte = afn[1]? afn[1].bind(component) : null;
var fnReadWord = afn[2]? afn[2].bind(component) : null;
var fnWriteWord = afn[3]? afn[3].bind(component) : null;
var nRegs = afn[5] || 1;
/*
* As discussed in the IOController comments above, when handlers are being registered for these
@ -1360,9 +1359,11 @@ BusPDP11.prototype.addIOTable = function(component, table, msgCategory, sName)
}
var sReg = afn[4];
var nRegs = afn[5] || 1;
for (var iReg = 0; iReg < nRegs; iReg++, addr += 2) {
if (sReg && nRegs > 1) sReg = afn[4] + iReg;
if (!this.addIOHandlers(addr, addr, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, msgCategory || MessagesPDP11.BUS, sReg || sName)) {
if (!this.addIOHandlers(addr, addr, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, component.bitsMessage || MessagesPDP11.BUS, sReg || component.idComponent)) {
return false;
}
}

View file

@ -1471,6 +1471,42 @@ PDP11.opRESET = function(opCode)
{
if (!(this.regPSW & PDP11.PSW.CMODE)) {
this.resetCPU();
if (this.panel) {
/*
* The PDP-11/70 XXDP test "EKBBF0" reports the following, with PANEL messages on ("m panel on"):
*
* CNSW.writeWord(177570,000101) @033502
* CNSW.readWord(177570): 000000 @032114
* LOOK AT THE CONSOLE LIGHTS
* THE DATA LIGHTS SHOULD READ 166667
* THE ADDRESS LIGHTS SHOULD READ CNSW.readWord(177570): 000000 @032150
* 032236
* CHANGE SWITCH 7 TO CONTINUE
* CNSW.readWord(177570): 000000 @032236
* stopped (31518011 instructions, 358048873 cycles, 58644 ms, 6105465 hz)
* R0=166667 R1=002362 R2=000000 R3=000000 R4=000000 R5=026642
* SP=001074 PC=032236 PS=000344 SR=00000000 T0 N0 Z1 V0 C0
* 032236: 032737 000200 177570 BIT #200,@#177570
* >> tr
* CNSW.readWord(177570): 000000 @032236 (cpu halted)
* R0=166667 R1=002362 R2=000000 R3=000000 R4=000000 R5=026642
* SP=001074 PC=032244 PS=000344 SR=00000000 T0 N0 Z1 V0 C0
* 032244: 001773 BEQ 032234 ;cycles=0
* >> tr
* R0=166667 R1=002362 R2=000000 R3=000000 R4=000000 R5=026642
* SP=001074 PC=032234 PS=000344 SR=00000000 T0 N0 Z1 V0 C0
* 032234: 000005 RESET ;cycles=5
*
* It's a little hard to see why the DATA lights should read 166667, since the PANEL messages indicate
* that the last CNSW.writeWord(177570) was for 000101, not 166667. So I'm guessing that the RESET
* instruction is supposed to propagate R0 to the console's DISPLAY register.
*
* This is similar to what we do for the HALT instruction on the PDP-11/20. None of these Console features
* seem to be very well documented (assuming they exist).
*/
this.panel.setData(this.regsGen[0], true);
}
}
this.nStepCycles -= 667; // TODO: Review (but it's definitely a big number)
};

View file

@ -222,7 +222,7 @@ CPUStatePDP11.prototype.initRegs = function()
this.dstMode = this.dstReg = this.dstAddr = 0;
this.trapPSW = -1;
this.resetRegs();
this.resetMMU();
};
/**
@ -233,15 +233,15 @@ CPUStatePDP11.prototype.initRegs = function()
CPUStatePDP11.prototype.resetCPU = function()
{
this.bus.reset();
this.resetRegs();
this.resetMMU();
};
/**
* resetRegs()
* resetMMU()
*
* @this {CPUStatePDP11}
*/
CPUStatePDP11.prototype.resetRegs = function()
CPUStatePDP11.prototype.resetMMU = function()
{
this.regSL = 0xff; // 177774
this.regErr = 0; // 177766

View file

@ -40,6 +40,7 @@ var MessagesPDP11 = {
MEMORY: 0x00000080,
ROM: 0x00000100,
DEVICE: 0x00000200,
PANEL: 0x00000400,
KEYBOARD: 0x00010000,
KEYS: 0x00020000,
PAPER: 0x00100000,
@ -75,6 +76,7 @@ MessagesPDP11.CATEGORIES = {
"memory": MessagesPDP11.MEMORY,
"rom": MessagesPDP11.ROM,
"device": MessagesPDP11.DEVICE,
"panel": MessagesPDP11.PANEL,
"keyboard": MessagesPDP11.KEYBOARD, // "kbd" is also allowed as shorthand for "keyboard"; see doMessages()
"key": MessagesPDP11.KEYS, // using "key" instead of "keys", since the latter is a method on JavasScript objects
"paper": MessagesPDP11.PAPER,

View file

@ -33,13 +33,14 @@
"use strict";
if (NODE) {
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var PDP11 = require("./defines");
var BusPDP11 = require("./bus");
var MemoryPDP11 = require("./memory");
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var PDP11 = require("./defines");
var BusPDP11 = require("./bus");
var MemoryPDP11 = require("./memory");
var MessagesPDP11 = require("./messages");
}
/**
@ -53,7 +54,7 @@ if (NODE) {
*/
function PanelPDP11(parmsPanel)
{
Component.call(this, "Panel", parmsPanel, PanelPDP11);
Component.call(this, "Panel", parmsPanel, PanelPDP11, MessagesPDP11.PANEL);
/*
* If there are any live registers, LEDs, etc, to display, this will provide a count.
@ -573,8 +574,7 @@ PanelPDP11.prototype.processStart = function(value, index)
* is depressed, "the computer system will be cleared." I take it to mean that it performs
* the equivalent of a RESET instruction.
*/
this.bus.reset();
this.cpu.resetRegs();
this.cpu.resetCPU();
/*
* The PDP-11/70 Handbook goes on to say: "If the system needs to be initialized but execution
* is not wanted, the START switch should be depressed while the HALT/ENABLE switch is in the HALT

View file

@ -282,7 +282,7 @@ RL11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.triggerInterrupt = this.cpu.addTrigger(PDP11.RL11.VEC, PDP11.RL11.PRI);
bus.addIOTable(this, RL11.UNIBUS_IOTABLE, MessagesPDP11.DISK);
bus.addIOTable(this, RL11.UNIBUS_IOTABLE);
bus.addResetHandler(this.reset.bind(this));
this.addDisk("None", RL11.SOURCE.NONE, true);

View file

@ -65,7 +65,7 @@ if (NODE) {
*/
function ROMPDP11(parmsROM)
{
Component.call(this, "ROM", parmsROM, ROMPDP11);
Component.call(this, "ROM", parmsROM, ROMPDP11, MessagesPDP11.ROM);
this.abInit = null;
this.aSymbols = null;
@ -289,11 +289,16 @@ ROMPDP11.prototype.addROM = function(addr)
* of the IOPAGE address space, by installing I/O handlers for the entire range that return the corresponding
* bytes of the current ROM image on reads, and ignore any writes (which I'm only assuming is how a typical
* ROM "device" deals with writes; if we remove the write handler, then writes will fault).
*
* TODO: It would be more efficient if we parsed ROM data as words rather than bytes, and then installed
* only word handlers instead of only byte handlers. It was done this way purely for historical reasons (ie,
* because that's how other PCjs machines parse their ROMs). For now, all this means is that executing code
* out of ROM will be slower than out of RAM -- although that's often true in the real world as well.
*/
var IOTable = {
[addr]: [ROMPDP11.prototype.readROMByte, ROMPDP11.prototype.writeROMByte, null, null, null, this.sizeROM >> 1]
};
if (this.bus.addIOTable(this, IOTable, MessagesPDP11.ROM, this.idComponent)) {
if (this.bus.addIOTable(this, IOTable)) {
this.fRetainROM = true;
return true;
}