More PDP-11 front panel functionality
This commit is contained in:
parent
99af96a113
commit
caf0a728f8
20 changed files with 1379 additions and 615 deletions
|
|
@ -186,6 +186,7 @@ CPUPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.cmp = cmp;
|
||||
this.bus = bus;
|
||||
this.dbg = dbg;
|
||||
this.panel = cmp.panel;
|
||||
|
||||
for (var i = 0; i < CPUPDP11.BUTTONS.length; i++) {
|
||||
var control = this.bindings[CPUPDP11.BUTTONS[i]];
|
||||
|
|
|
|||
|
|
@ -1411,8 +1411,8 @@ PDP11.opNOP = function(opCode)
|
|||
PDP11.opRESET = function(opCode)
|
||||
{
|
||||
if (!(this.regPSW & PDP11.PSW.CMODE)) {
|
||||
this.resetRegs();
|
||||
this.bus.reset();
|
||||
this.resetRegs();
|
||||
// display.data = this.regsGen[0]; // TODO: Review
|
||||
}
|
||||
this.nStepCycles -= 667; // TODO: Review (but it's definitely a big number)
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ CPUStatePDP11.prototype.setMMR0 = function(newMMR0)
|
|||
this.mmuEnable = mmuEnable;
|
||||
this.setMemoryAccess();
|
||||
}
|
||||
if (this.panel) this.panel.updateStatus();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -357,6 +358,7 @@ CPUStatePDP11.prototype.setMMR3 = function(newMMR3)
|
|||
this.regMMR3 = newMMR3;
|
||||
this.mmuMask = (newMMR3 & PDP11.MMR3.MMU_22BIT)? 0x3fffff : 0x3ffff;
|
||||
this.setMemoryAccess();
|
||||
if (this.panel) this.panel.updateStatus();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ var PDP11 = {
|
|||
XCSR: 0o177564, // Display Terminal: Transmitter Status Register
|
||||
XBUF: 0o177566, // Display Terminal: Transmitter Data Buffer Register
|
||||
|
||||
CNSL: 0o177570, // Console Switch and Front Panel Display
|
||||
CNSW: 0o177570, // Console (Front Panel) Switch Register
|
||||
|
||||
MMR0: 0o177572, // 777572 17777572
|
||||
MMR1: 0o177574, // 777574 17777574
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ if (NODE) {
|
|||
* The Device component implements the following "default" devices:
|
||||
*
|
||||
* KW11 (KW11-L Line Time Clock)
|
||||
* CNSL (Console Switch and Front Panel Display)
|
||||
*
|
||||
* as well providing access to all the MMU and CPU registers, PSW, etc.
|
||||
*
|
||||
|
|
@ -61,13 +60,6 @@ function DevicePDP11(parmsDevice)
|
|||
{
|
||||
Component.call(this, "Device", parmsDevice, DevicePDP11, MessagesPDP11.DEVICE);
|
||||
|
||||
this.console = { // CNSL registers
|
||||
data: 0,
|
||||
address: 0,
|
||||
misc: 0x14,
|
||||
switches: 0
|
||||
};
|
||||
|
||||
this.kw11 = { // LW11 registers
|
||||
csr: 0,
|
||||
timer: -1 // initBus() will initialize this timer ID
|
||||
|
|
@ -146,7 +138,6 @@ DevicePDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
*/
|
||||
DevicePDP11.prototype.reset = function()
|
||||
{
|
||||
this.console.misc = (this.console.misc & ~0x77) | 0x14; // kernel 16 bit
|
||||
this.kw11.lks = 0;
|
||||
};
|
||||
|
||||
|
|
@ -194,33 +185,6 @@ DevicePDP11.prototype.writeLKS = function(data, addr)
|
|||
this.kw11.lks = data & ~PDP11.KW11.LKS.MON;
|
||||
};
|
||||
|
||||
/**
|
||||
* readCNSL(addr)
|
||||
*
|
||||
* If addr is set, then this a normal read, so we should return normal results (ie, switches);
|
||||
* if addr is NOT set, then this is a read-before-write, so we must return the value being updated (ie, data).
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.CNSL or 177570)
|
||||
* @return {number}
|
||||
*/
|
||||
DevicePDP11.prototype.readCNSL = function(addr)
|
||||
{
|
||||
return (addr? this.console.switches : this.console.data) & 0xffff;
|
||||
};
|
||||
|
||||
/**
|
||||
* writeCNSL(data, addr)
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {number} data
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.CNSL or 177570)
|
||||
*/
|
||||
DevicePDP11.prototype.writeCNSL = function(data, addr)
|
||||
{
|
||||
this.console.data = data;
|
||||
};
|
||||
|
||||
/**
|
||||
* readMMR0(addr)
|
||||
*
|
||||
|
|
@ -243,7 +207,6 @@ DevicePDP11.prototype.readMMR0 = function(addr)
|
|||
DevicePDP11.prototype.writeMMR0 = function(data, addr)
|
||||
{
|
||||
this.cpu.setMMR0(data);
|
||||
this.updateConsoleMode();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -304,21 +267,6 @@ DevicePDP11.prototype.readMMR3 = function(addr)
|
|||
DevicePDP11.prototype.writeMMR3 = function(data, addr)
|
||||
{
|
||||
this.cpu.setMMR3(data);
|
||||
this.updateConsoleMode();
|
||||
};
|
||||
|
||||
/**
|
||||
* updateConsoleMode()
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
*/
|
||||
DevicePDP11.prototype.updateConsoleMode = function()
|
||||
{
|
||||
/*
|
||||
* Set bit to 1 (22-bit), 2 (18-bit), or 4 (16-bit)
|
||||
*/
|
||||
var bit = this.cpu.mmuEnable? ((this.cpu.regMMR3 & PDP11.MMR3.MMU_22BIT)? 1 : 2) : 4;
|
||||
this.console.misc = (this.console.misc & ~7) | bit;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1105,7 +1053,6 @@ DevicePDP11.UNIBUS_IOTABLE = {
|
|||
[PDP11.UNIBUS.KDSAR0]: /* 172360 */ [null, null, DevicePDP11.prototype.readKDSAR, DevicePDP11.prototype.writeKDSAR, "KDSAR", 8, PDP11.MODEL_1145],
|
||||
[PDP11.UNIBUS.MMR3]: /* 172516 */ [null, null, DevicePDP11.prototype.readMMR3, DevicePDP11.prototype.writeMMR3, "MMR3", 1, PDP11.MODEL_1145],
|
||||
[PDP11.UNIBUS.LKS]: /* 177546 */ [null, null, DevicePDP11.prototype.readLKS, DevicePDP11.prototype.writeLKS, "LKS"],
|
||||
[PDP11.UNIBUS.CNSL]: /* 177570 */ [null, null, DevicePDP11.prototype.readCNSL, DevicePDP11.prototype.writeCNSL, "CNSL"],
|
||||
[PDP11.UNIBUS.MMR0]: /* 177572 */ [null, null, DevicePDP11.prototype.readMMR0, DevicePDP11.prototype.writeMMR0, "MMR0", 1, PDP11.MODEL_1145],
|
||||
[PDP11.UNIBUS.MMR1]: /* 177574 */ [null, null, DevicePDP11.prototype.readMMR1, DevicePDP11.prototype.writeIgnored, "MMR1", 1, PDP11.MODEL_1145],
|
||||
[PDP11.UNIBUS.MMR2]: /* 177576 */ [null, null, DevicePDP11.prototype.readMMR2, DevicePDP11.prototype.writeIgnored, "MMR2", 1, PDP11.MODEL_1145],
|
||||
|
|
|
|||
|
|
@ -54,19 +54,112 @@ if (NODE) {
|
|||
function PanelPDP11(parmsPanel)
|
||||
{
|
||||
Component.call(this, "Panel", parmsPanel, PanelPDP11);
|
||||
|
||||
/*
|
||||
* If there are any live registers, LEDs, etc, to display, this will provide a count.
|
||||
*
|
||||
* TODO: Add some UI for fDisplayLiveRegs (either an XML property, or a UI checkbox, or both).
|
||||
*/
|
||||
this.cLiveRegs = 0;
|
||||
/*
|
||||
* TODO: Add some UI for displayLiveRegs (either an XML property, or a UI checkbox, or both)
|
||||
*/
|
||||
this.flags.displayLiveRegs = true;
|
||||
this.fDisplayLiveRegs = true;
|
||||
this.fLampTest = false;
|
||||
this.fExamine = this.fDeposit = false;
|
||||
|
||||
/*
|
||||
* regCNSW contains the Console (Front Panel) Switch Register, which is also available as a
|
||||
* read-only register at 177570 (but only the low 16 bits).
|
||||
*
|
||||
* regAddr is an internal register containing the contents of the Front Panel's ADDRESS display,
|
||||
* and regData corresponds to the DATA display. They are updated by setAddr() and setData(),
|
||||
* which in turn take care of calling updateLEDArray().
|
||||
*/
|
||||
this.regCNSW = 0;
|
||||
this.regAddr = this.regData = 0;
|
||||
this.regMisc = 0x14;
|
||||
|
||||
/*
|
||||
* Every LED has a simple numeric value, assigned when setBinding() is called:
|
||||
*
|
||||
* 0 if off, 1 if on
|
||||
*
|
||||
* initBus() will call updateLEDs() to ensure that every LED is set to its initial value.
|
||||
*/
|
||||
this.leds = {};
|
||||
|
||||
/*
|
||||
* Every switch has an array associated with it:
|
||||
*
|
||||
* [0]: initial/current value of switch (0 if down, 1 if up)
|
||||
* [1]: true if the switch is momentary, false if not
|
||||
* [2]: true if the switch is currently being pressed, false if not
|
||||
* [3]: optional handler to call whenever the switch is pressed or released
|
||||
* [4]: optional switch index (used with CNSW switches 'S0' through 'S21')
|
||||
*
|
||||
* initBus() will call updateSwitches() to ensure that every switch is the position represented below.
|
||||
*
|
||||
* NOTE: Not all switches have the same "process" criteria. For example, 'TEST' will perform a lamp test
|
||||
* when it is momentarily pressed "up", whereas 'LOAD [ADRS]' will load the address register from the switch
|
||||
* register when it is momentarily pressed "down".
|
||||
*
|
||||
* This means that processLampTest(value) must act when value == 1, whereas processLoadAddr(value) must
|
||||
* act when value == 0. You can infer all this from the table below, because the initial value of any
|
||||
* momentary switch is its "passive" value, so the opposite is its "active" value.
|
||||
*/
|
||||
this.switches = {
|
||||
'START': [1, true, false, this.processStart],
|
||||
'STEP': [1, false, false, this.processStep],
|
||||
'ENABLE': [1, false, false, this.processEnable],
|
||||
'CONT': [1, true, false, this.processContinue],
|
||||
'DEP': [0, true, false, this.processDeposit],
|
||||
'EXAM': [1, true, false, this.processExamine],
|
||||
'LOAD': [1, true, false, this.processLoadAddr],
|
||||
'TEST': [0, true, false, this.processLampTest]
|
||||
};
|
||||
for (var i = 0; i < 22; i++) {
|
||||
this.switches['S'+i] = [0, false, false, this.processSwitchReg, i];
|
||||
}
|
||||
}
|
||||
|
||||
Component.subclass(PanelPDP11);
|
||||
|
||||
/*
|
||||
* To get the current state of a switch; eg::
|
||||
*
|
||||
* this.getSwitch(PanelPDP11.SWITCH.ENABLE)
|
||||
*
|
||||
* However, I haven't filled out this table, primarily because the only switches we need to query
|
||||
* are the non-momentary ones (eg, ENABLE and STEP), and EXAM and DEP (because they have special
|
||||
* "step" behavior when pressed more than once in a row).
|
||||
*/
|
||||
PanelPDP11.SWITCH = {
|
||||
DEP: 'DEP',
|
||||
ENABLE: 'ENABLE',
|
||||
EXAM: 'EXAM',
|
||||
STEP: 'STEP'
|
||||
};
|
||||
|
||||
/**
|
||||
* getSwitch(name)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} name
|
||||
* @return {number|undefined} 0 if switch is off ("down"), 1 if on ("up"), or undefined if unrecognized
|
||||
*/
|
||||
PanelPDP11.prototype.getSwitch = function(name)
|
||||
{
|
||||
return this.switches[name] && this.switches[name][0];
|
||||
};
|
||||
|
||||
/**
|
||||
* reset()
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
*/
|
||||
PanelPDP11.prototype.reset = function()
|
||||
{
|
||||
this.regMisc = (this.regMisc & ~0x77) | 0x14; // kernel 16 bit
|
||||
};
|
||||
|
||||
/**
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
|
|
@ -93,29 +186,72 @@ PanelPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
|||
if (DEBUGGER && this.dbg && this.dbg.setBinding(sType, sBinding, control, sValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (sBinding) {
|
||||
case "R0":
|
||||
case "R1":
|
||||
case "R2":
|
||||
case "R3":
|
||||
case "R4":
|
||||
case "R5":
|
||||
case "R6":
|
||||
case "R7":
|
||||
case "NF":
|
||||
case "ZF":
|
||||
case "VF":
|
||||
case "CF":
|
||||
case "PS":
|
||||
case 'R0':
|
||||
case 'R1':
|
||||
case 'R2':
|
||||
case 'R3':
|
||||
case 'R4':
|
||||
case 'R5':
|
||||
case 'R6':
|
||||
case 'R7':
|
||||
case 'NF':
|
||||
case 'ZF':
|
||||
case 'VF':
|
||||
case 'CF':
|
||||
case 'PS':
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
return true;
|
||||
|
||||
default:
|
||||
if (sType == "rled") {
|
||||
/*
|
||||
* Square (default) or round LEDs are defined in machine XML files like so:
|
||||
*
|
||||
* <control type="rled" binding="A3" value="1" width="100%" container="center"/>
|
||||
*
|
||||
* Only *type* and *binding* attributes are required; if *value* is omitted, the default value is 0 (off).
|
||||
*/
|
||||
if (sType == "led" || sType == "rled") {
|
||||
this.bindings[sBinding] = control;
|
||||
this.leds[sBinding] = sValue? 1 : 0;
|
||||
this.cLiveRegs++;
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Switches are defined in machine XML files like so:
|
||||
*
|
||||
* <control type="switch" binding="S3" value="1" width="100%" container="center"/>
|
||||
*
|
||||
* Only *type* and *binding* attributes are required; if *value* is omitted, the default value is 0 ("down").
|
||||
*
|
||||
* Currently, there is no XML attribute to indicate whether a switch is "momentary"; only recognized switches
|
||||
* in our internal table can have that attribute.
|
||||
*/
|
||||
if (sType == "switch") {
|
||||
/*
|
||||
* Like LEDs, we allow unrecognized switches to be defined as well, but they won't do anything useful,
|
||||
* since only recognized switches will have handlers that perform the appropriate operations.
|
||||
*/
|
||||
if (this.switches[sBinding] === undefined) {
|
||||
this.switches[sBinding] = [sValue? 1 : 0];
|
||||
}
|
||||
this.bindings[sBinding] = control;
|
||||
var parent = control.parentElement || control;
|
||||
parent = parent.parentElement || parent;
|
||||
parent.onmousedown = function(panel, sBinding) {
|
||||
return function onPressSwitch() {
|
||||
panel.pressSwitch(sBinding);
|
||||
};
|
||||
}(this, sBinding);
|
||||
parent.onmouseup = parent.onmouseout = function(panel, sBinding) {
|
||||
return function onReleaseSwitch() {
|
||||
panel.releaseSwitch(sBinding);
|
||||
};
|
||||
}(this, sBinding);
|
||||
return true;
|
||||
}
|
||||
return this.parent.setBinding.call(this, sType, sBinding, control, sValue);
|
||||
}
|
||||
};
|
||||
|
|
@ -135,6 +271,12 @@ PanelPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
||||
bus.addIOTable(this, PanelPDP11.UNIBUS_IOTABLE);
|
||||
bus.addResetHandler(this.reset.bind(this));
|
||||
|
||||
this.updateLEDs();
|
||||
this.updateSwitches();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -147,7 +289,20 @@ PanelPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
*/
|
||||
PanelPDP11.prototype.powerUp = function(data, fRepower)
|
||||
{
|
||||
if (!fRepower) PanelPDP11.init();
|
||||
if (!fRepower) {
|
||||
/*
|
||||
* As noted in init(), our powerUp() method gives us a second opportunity to notify any
|
||||
* components that that might care (eg, CPU, Keyboard, and Debugger) that we have some controls
|
||||
* they might want to use.
|
||||
*/
|
||||
PanelPDP11.init();
|
||||
/*
|
||||
* TODO: Until we implement a restore() function, all we can do is reset(); however, that's
|
||||
* currently unnecessary, since we've added reset() to the addResetHandler() list.
|
||||
*
|
||||
* this.reset();
|
||||
*/
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -184,7 +339,7 @@ PanelPDP11.prototype.updateValue = function(sLabel, nValue, cch)
|
|||
}
|
||||
var sVal;
|
||||
var nBase = this.dbg && this.dbg.nBase || 8;
|
||||
if (!this.cpu.isRunning() || this.flags.displayLiveRegs) {
|
||||
if (!this.cpu.isRunning() || this.fDisplayLiveRegs) {
|
||||
sVal = nBase == 8? str.toOct(nValue, cch) : str.toHex(nValue, cch);
|
||||
} else {
|
||||
sVal = "--------".substr(0, cch || 4);
|
||||
|
|
@ -200,39 +355,308 @@ PanelPDP11.prototype.updateValue = function(sLabel, nValue, cch)
|
|||
};
|
||||
|
||||
/**
|
||||
* setLED(control, f)
|
||||
* setLED(sBinding, value)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {Object} control is an HTML control DOM object
|
||||
* @param {boolean|number} f is true if the LED represented by control should be "on", false if "off"
|
||||
* @param {string} sBinding
|
||||
* @param {boolean|number} value (true if the LED should be on, false if off)
|
||||
*/
|
||||
PanelPDP11.prototype.setLED = function(control, f)
|
||||
PanelPDP11.prototype.setLED = function(sBinding, value)
|
||||
{
|
||||
/*
|
||||
* TODO: Add support for user-definable LED colors
|
||||
*/
|
||||
control.style.backgroundColor = (f? "#ff0000" : "#000000");
|
||||
var control = this.bindings[sBinding];
|
||||
if (control) {
|
||||
/*
|
||||
* TODO: Add support for user-definable LED colors?
|
||||
*/
|
||||
control.style.backgroundColor = (value? "#ff0000" : "#000000");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateLEDs(sPrefix, data, nLEDs)
|
||||
* updateLEDs(override)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {boolean|number|null} [override] (true turn on all LEDs, false to turn off all LEDs, null or undefined for normal LED activity)
|
||||
*/
|
||||
PanelPDP11.prototype.updateLEDs = function(override)
|
||||
{
|
||||
for (var sBinding in this.leds) {
|
||||
this.setLED(sBinding, override != null? override : this.leds[sBinding]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateLEDArray(sPrefix, data, nLEDs)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sPrefix
|
||||
* @param {number} data
|
||||
* @param {number} nLEDs
|
||||
*/
|
||||
PanelPDP11.prototype.updateLEDs = function(sPrefix, data, nLEDs)
|
||||
PanelPDP11.prototype.updateLEDArray = function(sPrefix, data, nLEDs)
|
||||
{
|
||||
for (var i = 0; i < nLEDs; i++) {
|
||||
var id = sPrefix + i;
|
||||
var control = this.bindings[id];
|
||||
if (control) {
|
||||
this.setLED(control, data & (1 << i));
|
||||
var sBinding = sPrefix + i;
|
||||
this.setLED(sBinding, data & (1 << i));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setSwitch(sBinding, value)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sBinding
|
||||
* @param {boolean|number} value (true if the switch should be "up" (on), false if "down" (off))
|
||||
*/
|
||||
PanelPDP11.prototype.setSwitch = function(sBinding, value)
|
||||
{
|
||||
var control = this.bindings[sBinding];
|
||||
if (control) {
|
||||
control.style.marginTop = (value? "0px" : "20px");
|
||||
control.style.backgroundColor = (value? "#00ff00" : "#228B22");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* pressSwitch(sBinding)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sBinding
|
||||
*/
|
||||
PanelPDP11.prototype.pressSwitch = function(sBinding)
|
||||
{
|
||||
var sw = this.switches[sBinding];
|
||||
this.setSwitch(sBinding, sw[0] = 1 - sw[0]);
|
||||
sw[2] = true;
|
||||
if (sw[3]) sw[3].call(this, sw[0], sw[4]);
|
||||
this.fDeposit = (sBinding == PanelPDP11.SWITCH.DEP);
|
||||
this.fExamine = (sBinding == PanelPDP11.SWITCH.EXAM);
|
||||
};
|
||||
|
||||
/**
|
||||
* releaseSwitch(sBinding)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sBinding
|
||||
*/
|
||||
PanelPDP11.prototype.releaseSwitch = function(sBinding)
|
||||
{
|
||||
/*
|
||||
* pressSwitch() is simple: flip the switch's current value in sw[0] and marked it "pressed" in sw[2].
|
||||
*
|
||||
* releaseSwitch() is more complicated, because we must handle both mouseUp and mouseOut events. The first time
|
||||
* we receive EITHER of those events AND the switch is marked momentary (sw[1]) AND the switch is pressed (sw[2]),
|
||||
* then we must flip the switch back to its original value.
|
||||
*
|
||||
* Otherwise, the only thing we have to do is mark the switch as no longer "pressed" (ie, set sw[2] to false).
|
||||
*/
|
||||
var sw = this.switches[sBinding];
|
||||
if (sw[1] && sw[2]) {
|
||||
this.setSwitch(sBinding, sw[0] = 1 - sw[0]);
|
||||
if (sw[3]) sw[3].call(this, sw[0], sw[4]);
|
||||
}
|
||||
sw[2] = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* processStart(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processStart = function(value, index)
|
||||
{
|
||||
if (!value && !this.cpu.isRunning()) {
|
||||
/*
|
||||
* TODO: Verify what the PDP-11/70 Handbook means when it says that when the 'START' switch
|
||||
* 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();
|
||||
/*
|
||||
* 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
|
||||
* position."
|
||||
*/
|
||||
if (this.getSwitch(PanelPDP11.SWITCH.ENABLE)) {
|
||||
this.cpu.startCPU();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processStep(value, index)
|
||||
*
|
||||
* If value == 1 (our initial value), then the 'STEP' switch is set to "S INST" (step one instruction);
|
||||
* otherwise, it's set to "S BUS CYCLE" (step one bus cycle). Note that we don't actually support the
|
||||
* latter.
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processStep = function(value, index)
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* processEnable(value, index)
|
||||
*
|
||||
* If value == 1 (our initial value), then the 'ENABLE'/'HALT' switch is set to 'ENABLE', otherwise 'HALT'.
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processEnable = function(value, index)
|
||||
{
|
||||
/*
|
||||
* The "down" (0) position is 'HALT', which stops the CPU; however, the "up" (1) position ('ENABLE')
|
||||
* does NOT start the CPU. You must press 'CONT' to continue execution, which will either continue for
|
||||
* one instruction if this switch to set to 'HALT' or indefinitely if it is set to 'ENABLE'.
|
||||
*/
|
||||
if (!value) {
|
||||
this.cpu.stopCPU();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processContinue(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processContinue = function(value, index)
|
||||
{
|
||||
if (!value && !this.cpu.isRunning()) {
|
||||
if (!this.getSwitch(PanelPDP11.SWITCH.ENABLE)) {
|
||||
/*
|
||||
* TODO: Technically, we're also supposed to check the 'STEP' switch to determine if we should
|
||||
* step one instruction or just one cycle, but we don't currently have the ability to do the latter.
|
||||
*/
|
||||
var dbg = this.dbg;
|
||||
if (dbg && !dbg.isBusy(true)) {
|
||||
dbg.setBusy(true);
|
||||
dbg.stepCPU(0);
|
||||
dbg.setBusy(false);
|
||||
} else {
|
||||
this.cpu.stepCPU(1);
|
||||
this.updateStatus();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.cpu.startCPU();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processDeposit(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processDeposit = function(value, index)
|
||||
{
|
||||
if (value && !this.cpu.isRunning()) {
|
||||
if (this.fDeposit) {
|
||||
this.setAddr(this.regAddr + 2);
|
||||
}
|
||||
this.bus.setWordDirect(this.regAddr, this.setData(this.regCNSW));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processExamine(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processExamine = function(value, index)
|
||||
{
|
||||
if (!value && !this.cpu.isRunning()) {
|
||||
if (this.fExamine) {
|
||||
this.setAddr(this.regAddr + 2);
|
||||
}
|
||||
this.setData(this.bus.getWordDirect(this.regAddr));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processLoadAddr(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processLoadAddr = function(value, index)
|
||||
{
|
||||
if (!value && !this.cpu.isRunning()) {
|
||||
this.setAddr(this.regCNSW);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* processLampTest(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @param {number} [index]
|
||||
*/
|
||||
PanelPDP11.prototype.processLampTest = function(value, index)
|
||||
{
|
||||
this.updateLEDs(value || null);
|
||||
};
|
||||
|
||||
/**
|
||||
* processSwitchReg(value, index)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value (normally 0 or 1, but we only depend on it being zero or non-zero)
|
||||
* @param {number} index
|
||||
*/
|
||||
PanelPDP11.prototype.processSwitchReg = function(value, index)
|
||||
{
|
||||
if (value) {
|
||||
this.regCNSW |= 1 << index;
|
||||
} else {
|
||||
this.regCNSW &= ~(1 << index);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setAddr(value)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @return {number}
|
||||
*/
|
||||
PanelPDP11.prototype.setAddr = function(value)
|
||||
{
|
||||
this.regAddr = value & this.bus.nBusMask;
|
||||
this.updateLEDArray("A", this.regAddr, 22);
|
||||
return this.regAddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* setData(value)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} value
|
||||
* @return {number}
|
||||
*/
|
||||
PanelPDP11.prototype.setData = function(value)
|
||||
{
|
||||
this.regData = value & 0xffff;
|
||||
this.updateLEDArray("D", this.regData, 16);
|
||||
return this.regData;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus(fForce)
|
||||
*
|
||||
|
|
@ -242,7 +666,7 @@ PanelPDP11.prototype.updateLEDs = function(sPrefix, data, nLEDs)
|
|||
PanelPDP11.prototype.updateStatus = function(fForce)
|
||||
{
|
||||
if (this.cLiveRegs) {
|
||||
if (fForce || !this.cpu.isRunning() || this.flags.displayLiveRegs) {
|
||||
if (fForce || !this.cpu.isRunning() || this.fDisplayLiveRegs) {
|
||||
for (var i = 0; i < this.cpu.regsGen.length; i++) {
|
||||
this.updateValue('R'+i, this.cpu.regsGen[i]);
|
||||
}
|
||||
|
|
@ -252,12 +676,62 @@ PanelPDP11.prototype.updateStatus = function(fForce)
|
|||
this.updateValue("ZF", (regPSW & PDP11.PSW.ZF)? 1 : 0, 1);
|
||||
this.updateValue("VF", (regPSW & PDP11.PSW.VF)? 1 : 0, 1);
|
||||
this.updateValue("CF", (regPSW & PDP11.PSW.CF)? 1 : 0, 1);
|
||||
this.updateLEDs("D", this.cpu.regsGen[0], 16);
|
||||
this.updateLEDs("A", this.cpu.regsGen[7], 22);
|
||||
if (!this.fLampTest) {
|
||||
this.setData(this.cpu.regsGen[0]);
|
||||
this.setAddr(this.cpu.regsGen[7]);
|
||||
/*
|
||||
* Set bit to 1 (22-bit), 2 (18-bit), or 4 (16-bit)
|
||||
*/
|
||||
var bit = this.cpu.mmuEnable? ((this.cpu.regMMR3 & PDP11.MMR3.MMU_22BIT)? 1 : 2) : 4;
|
||||
// this.misc = (this.misc & ~7) | bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateSwitches()
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
*/
|
||||
PanelPDP11.prototype.updateSwitches = function()
|
||||
{
|
||||
for (var sBinding in this.switches) {
|
||||
this.setSwitch(sBinding, this.switches[sBinding][0]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* readCNSW(addr)
|
||||
*
|
||||
* If addr is set, then this a normal read, so we should return normal results (ie, switches);
|
||||
* if addr is NOT set, then this is a read-before-write, so we must return the value being updated (ie, data).
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.CNSW or 177570)
|
||||
* @return {number}
|
||||
*/
|
||||
PanelPDP11.prototype.readCNSW = function(addr)
|
||||
{
|
||||
return (addr? this.regCNSW : this.regData) & 0xffff;
|
||||
};
|
||||
|
||||
/**
|
||||
* writeCNSW(data, addr)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {number} data
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.CNSW or 177570)
|
||||
*/
|
||||
PanelPDP11.prototype.writeCNSW = function(data, addr)
|
||||
{
|
||||
this.regData = data;
|
||||
};
|
||||
|
||||
PanelPDP11.UNIBUS_IOTABLE = {
|
||||
[PDP11.UNIBUS.CNSW]: /* 177570 */ [null, null, PanelPDP11.prototype.readCNSW, PanelPDP11.prototype.writeCNSW, "CNSW"]
|
||||
};
|
||||
|
||||
/**
|
||||
* PanelPDP11.init()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -132,11 +132,19 @@
|
|||
.pcjs-tripled {
|
||||
padding: 1px;
|
||||
}
|
||||
.pcjs-tripled-label {
|
||||
.pcjs-ledlbl0 {
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
font-size: 50%;
|
||||
background-color: #8d4076;
|
||||
}
|
||||
.pcjs-ledlbl1 {
|
||||
text-align: right;
|
||||
font-size: 50%;
|
||||
background-color: #d83662;
|
||||
}
|
||||
.pcjs-ledpad {
|
||||
text-align: center;
|
||||
font-size: x-small;
|
||||
line-height: 32px;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
|
@ -159,6 +167,25 @@
|
|||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
}
|
||||
.pcjs-swlbl {
|
||||
text-align: center;
|
||||
font-size: 40%;
|
||||
line-height: 32px;
|
||||
background-color: #000000;
|
||||
}
|
||||
.pcjs-swpad {
|
||||
height: 32px;
|
||||
background-color: #000000;
|
||||
}
|
||||
.pcjs-switch {
|
||||
height: 10px;
|
||||
width: 28px;
|
||||
margin-top: 0%;
|
||||
max-width: 90%;
|
||||
background-color: #00ff00;
|
||||
}
|
||||
.pcjs-screen {
|
||||
clear: both;
|
||||
|
|
|
|||
|
|
@ -422,7 +422,10 @@
|
|||
</form>
|
||||
</xsl:when>
|
||||
<xsl:when test="@type = 'led' or @type = 'rled'">
|
||||
<div class="{$APPCLASS}-binding {$CSSCLASS}-{@type}" data-value="{{{$type},{$binding}}}" style="display:inline-block;"><xsl:value-of select="."/></div>
|
||||
<div class="{$APPCLASS}-binding {$CSSCLASS}-{@type}" data-value="{{{$type},{$binding},{$value}}}" style="display:inline-block;"><xsl:value-of select="."/></div>
|
||||
</xsl:when>
|
||||
<xsl:when test="@type = 'switch'">
|
||||
<div class="{$APPCLASS}-binding {$CSSCLASS}-{@type}" data-value="{{{$type},{$binding},{$value}}}" style="display:inline-block;"><xsl:value-of select="."/></div>
|
||||
</xsl:when>
|
||||
<xsl:when test="@type = 'progress'">
|
||||
<div class="{$APPCLASS}-binding {$CSSCLASS}-{@type}" style="-webkit-user-select:none;{$border}{$width}{$height}{$fontsize}{$style}" data-value="{{{$type},{$binding},{$value}}}">
|
||||
|
|
|
|||
Loading…
Reference in a new issue