Added preliminary LED support
This commit is contained in:
parent
05626a33cb
commit
47767416a1
11 changed files with 493 additions and 498 deletions
|
|
@ -99,7 +99,7 @@ function CPU(parmsCPU, nCyclesDefault)
|
|||
this.flags.autoStart = parmsCPU['autoStart'];
|
||||
|
||||
/*
|
||||
* TODO: Add some UI for fDisplayLiveRegs (either an XML property, or a UI checkbox, or both)
|
||||
* TODO: Add some UI for displayLiveRegs (either an XML property, or a UI checkbox, or both)
|
||||
*/
|
||||
this.flags.displayLiveRegs = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -999,6 +999,7 @@ ComputerPDP11.prototype.start = function(ms, nCycles)
|
|||
component.start(ms, nCycles);
|
||||
}
|
||||
}
|
||||
this.updateStatus(true);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1023,19 +1024,20 @@ ComputerPDP11.prototype.stop = function(ms, nCycles)
|
|||
component.stop(ms, nCycles);
|
||||
}
|
||||
}
|
||||
this.updateStatus(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {ComputerPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
ComputerPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
ComputerPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
var computer = this;
|
||||
|
||||
|
|
|
|||
|
|
@ -126,11 +126,6 @@ function CPUPDP11(parmsCPU, nCyclesDefault)
|
|||
this.flags.starting = false;
|
||||
this.flags.autoStart = parmsCPU['autoStart'];
|
||||
|
||||
/*
|
||||
* TODO: Add some UI for fDisplayLiveRegs (either an XML property, or a UI checkbox, or both)
|
||||
*/
|
||||
this.flags.displayLiveRegs = false;
|
||||
|
||||
/*
|
||||
* Get checksum parameters, if any. runCPU() behavior is not affected until fChecksum
|
||||
* is true, which won't happen until resetChecksum() is called with nCyclesChecksumInterval
|
||||
|
|
@ -288,7 +283,7 @@ CPUPDP11.prototype.powerUp = function(data, fRepower)
|
|||
*
|
||||
* this.flags.powered = true;
|
||||
*/
|
||||
this.updateCPU();
|
||||
this.cmp.updateStatus();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -451,54 +446,18 @@ CPUPDP11.prototype.displayChecksum = function()
|
|||
};
|
||||
|
||||
/**
|
||||
* displayValue(sLabel, nValue, cch)
|
||||
*
|
||||
* This is principally for displaying register values, but in reality, it can be used to display any
|
||||
* numeric value bound to the given label.
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {CPUPDP11}
|
||||
* @param {string} sLabel
|
||||
* @param {number} nValue
|
||||
* @param {number} [cch]
|
||||
*/
|
||||
CPUPDP11.prototype.displayValue = function(sLabel, nValue, cch)
|
||||
{
|
||||
if (this.bindings[sLabel]) {
|
||||
if (nValue === undefined) {
|
||||
this.setError("Value for " + sLabel + " is invalid");
|
||||
this.stopCPU();
|
||||
}
|
||||
var sVal;
|
||||
var nBase = this.dbg && this.dbg.nBase || 8;
|
||||
if (!this.flags.running || this.flags.displayLiveRegs) {
|
||||
sVal = nBase == 8? str.toOct(nValue, cch) : str.toHex(nValue, cch);
|
||||
} else {
|
||||
sVal = "--------".substr(0, cch || 4);
|
||||
}
|
||||
/*
|
||||
* TODO: Determine if this test actually avoids any redrawing when a register hasn't changed, and/or if
|
||||
* we should maintain our own (numeric) cache of displayed register values (to avoid creating these temporary
|
||||
* string values that will have to garbage-collected), and/or if this is actually slower, and/or if I'm being
|
||||
* too obsessive.
|
||||
*/
|
||||
if (this.bindings[sLabel].textContent != sVal) this.bindings[sLabel].textContent = sVal;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {CPUPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "run")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
CPUPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
CPUPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
var cpu = this;
|
||||
var fBound = false;
|
||||
|
||||
switch (sBinding) {
|
||||
case "power":
|
||||
|
|
@ -509,8 +468,7 @@ CPUPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
* so we record those bindings here and pass them on to the Computer component in initBus().
|
||||
*/
|
||||
this.bindings[sBinding] = control;
|
||||
fBound = true;
|
||||
break;
|
||||
return true;
|
||||
|
||||
case "run":
|
||||
this.bindings[sBinding] = control;
|
||||
|
|
@ -526,13 +484,11 @@ CPUPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
else
|
||||
cpu.stopCPU();
|
||||
};
|
||||
fBound = true;
|
||||
break;
|
||||
return true;
|
||||
|
||||
case "speed":
|
||||
this.bindings[sBinding] = control;
|
||||
fBound = true;
|
||||
break;
|
||||
return true;
|
||||
|
||||
case "setSpeed":
|
||||
this.bindings[sBinding] = control;
|
||||
|
|
@ -540,13 +496,27 @@ CPUPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
cpu.setSpeed(cpu.nCyclesMultiplier << 1, true);
|
||||
};
|
||||
control.textContent = this.getSpeedTarget();
|
||||
fBound = true;
|
||||
break;
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return fBound;
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus(fForce)
|
||||
*
|
||||
* Some of the CPU bindings provide feedback and therefore need to be updated periodically. This is called
|
||||
* via the Computer's updateStatus() handler several times per second; see YIELDS_PER_STATUS.
|
||||
*
|
||||
* @this {CPUPDP11}
|
||||
* @param {boolean} [fForce]
|
||||
*/
|
||||
CPUPDP11.prototype.updateStatus = function(fForce)
|
||||
{
|
||||
var controlSpeed = this.bindings["speed"];
|
||||
if (controlSpeed) controlSpeed.textContent = this.getSpeedCurrent();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1111,7 +1081,6 @@ CPUPDP11.prototype.runCPU = function()
|
|||
}
|
||||
catch (e) {
|
||||
this.stopCPU();
|
||||
this.updateCPU();
|
||||
if (this.cmp) this.cmp.stop(usr.getTime(), this.getCycles());
|
||||
this.setError(e.stack || e.message);
|
||||
return;
|
||||
|
|
@ -1152,7 +1121,6 @@ CPUPDP11.prototype.startCPU = function(fUpdateFocus)
|
|||
if (fUpdateFocus) this.cmp.updateFocus(true);
|
||||
this.cmp.start(this.msStartRun, this.getCycles());
|
||||
}
|
||||
this.updateCPU(true);
|
||||
setTimeout(this.onRunTimeout, 0);
|
||||
return true;
|
||||
};
|
||||
|
|
@ -1194,29 +1162,10 @@ CPUPDP11.prototype.stopCPU = function(fComplete)
|
|||
if (this.cmp) {
|
||||
this.cmp.stop(usr.getTime(), this.getCycles());
|
||||
}
|
||||
this.updateCPU();
|
||||
}
|
||||
this.flags.complete = fComplete;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateCPU(fForce)
|
||||
*
|
||||
* This used to be performed at the end of every stepCPU(), but runCPU() -- which relies upon
|
||||
* stepCPU() -- needed to have more control over when these updates are performed. However, for
|
||||
* other callers of stepCPU(), such as the Debugger, the combination of stepCPU() + updateCPU()
|
||||
* provides the old behavior.
|
||||
*
|
||||
* @this {CPUPDP11}
|
||||
* @param {boolean} [fForce] (true to force a video update; used by the Debugger)
|
||||
*/
|
||||
CPUPDP11.prototype.updateCPU = function(fForce)
|
||||
{
|
||||
if (this.cmp) {
|
||||
this.cmp.updateStatus(fForce);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* yieldCPU()
|
||||
*
|
||||
|
|
@ -1232,10 +1181,10 @@ CPUPDP11.prototype.yieldCPU = function()
|
|||
// if (DEBUG) this.nSnapCycles = this.nBurstCycles;
|
||||
/*
|
||||
* The Debugger calls yieldCPU() after every message() to ensure browser responsiveness, but it looks
|
||||
* odd for those messages to show CPU state changes but for the CPU's own status display to not (ditto
|
||||
* for the Video display), so I've added this call to try to keep things looking synchronized.
|
||||
* odd for those messages to show CPU state changes if the Control Panel, Video display, etc, does not,
|
||||
* so I've added this call to try to keep things looking synchronized.
|
||||
*/
|
||||
this.updateCPU();
|
||||
this.cmp.updateStatus();
|
||||
};
|
||||
|
||||
if (NODE) module.exports = CPUPDP11;
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ function CPUStatePDP11(parmsCPU)
|
|||
|
||||
CPUPDP11.call(this, parmsCPU, nCyclesDefault);
|
||||
|
||||
/*
|
||||
* If there are no live registers to display, then updateStatus() can skip a bit....
|
||||
*/
|
||||
this.cLiveRegs = 0;
|
||||
|
||||
/*
|
||||
* Initialize processor operation to match the requested model
|
||||
*/
|
||||
|
|
@ -374,72 +369,6 @@ CPUStatePDP11.prototype.restore = function(data)
|
|||
return this.bus.restoreMemory(data[2]);
|
||||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "AX")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
CPUStatePDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
{
|
||||
var fBound = false;
|
||||
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":
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
fBound = true;
|
||||
break;
|
||||
default:
|
||||
fBound = this.parent.setBinding.call(this, sHTMLType, sBinding, control);
|
||||
break;
|
||||
}
|
||||
return fBound;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus(fForce)
|
||||
*
|
||||
* This provides periodic Control Panel updates (a few times per second; see YIELDS_PER_STATUS).
|
||||
* this is where we take care of any DOM updates (eg, register values) while the CPU is running.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {boolean} [fForce] (true will display registers even if the CPU is running and "live" registers are not enabled)
|
||||
*/
|
||||
CPUStatePDP11.prototype.updateStatus = function(fForce)
|
||||
{
|
||||
if (this.cLiveRegs) {
|
||||
if (fForce || !this.flags.running || this.flags.displayLiveRegs) {
|
||||
for (var i = 0; i < this.regsGen.length; i++) {
|
||||
this.displayValue('R'+i, this.regsGen[i]);
|
||||
}
|
||||
var regPSW = this.getPSW();
|
||||
this.displayValue("PS", regPSW);
|
||||
this.displayValue("NF", (regPSW & PDP11.PSW.NF)? 1 : 0, 1);
|
||||
this.displayValue("ZF", (regPSW & PDP11.PSW.ZF)? 1 : 0, 1);
|
||||
this.displayValue("VF", (regPSW & PDP11.PSW.VF)? 1 : 0, 1);
|
||||
this.displayValue("CF", (regPSW & PDP11.PSW.CF)? 1 : 0, 1);
|
||||
}
|
||||
}
|
||||
var controlSpeed = this.bindings["speed"];
|
||||
if (controlSpeed) controlSpeed.textContent = this.getSpeedCurrent();
|
||||
};
|
||||
|
||||
/**
|
||||
* clearCF()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -454,16 +454,16 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "debugInput")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
DebuggerPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
DebuggerPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
var dbg = this;
|
||||
switch (sBinding) {
|
||||
|
|
@ -626,7 +626,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.bus.setByteDirect(addr, b);
|
||||
if (inc) this.incAddr(dbgAddr, inc);
|
||||
this.cpu.updateCPU(true); // we set fForce to true in case video memory was the target
|
||||
this.cmp.updateStatus(true); // force a computer status update if, say, video memory was the target
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -644,7 +644,7 @@ if (DEBUGGER) {
|
|||
if (addr !== PDP11.ADDR_INVALID) {
|
||||
this.bus.setWordDirect(addr, w);
|
||||
if (inc) this.incAddr(dbgAddr, inc);
|
||||
this.cpu.updateCPU(true); // we set fForce to true in case video memory was the target
|
||||
this.cmp.updateStatus(true); // force a computer status update if, say, video memory was the target
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1242,15 +1242,15 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* stepCPU(nCycles, fRegs, fUpdateCPU)
|
||||
* stepCPU(nCycles, fRegs, fUpdateStatus)
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {number} nCycles (0 for one instruction without checking breakpoints)
|
||||
* @param {boolean} [fRegs] is true to display registers after step (default is false)
|
||||
* @param {boolean} [fUpdateCPU] is false to disable calls to updateCPU() (default is true)
|
||||
* @param {boolean} [fUpdateStatus] is false to disable Computer status updates (default is true)
|
||||
* @return {boolean}
|
||||
*/
|
||||
DebuggerPDP11.prototype.stepCPU = function(nCycles, fRegs, fUpdateCPU)
|
||||
DebuggerPDP11.prototype.stepCPU = function(nCycles, fRegs, fUpdateStatus)
|
||||
{
|
||||
if (!this.checkCPU()) return false;
|
||||
|
||||
|
|
@ -1291,11 +1291,11 @@ if (DEBUGGER) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Because we called cpu.stepCPU() and not cpu.startCPU(), we must nudge the cpu's update code,
|
||||
* and then update our own state. Normally, the only time fUpdateCPU will be false is when doTrace()
|
||||
* is calling us in a loop, in which case it will perform its own updateCPU() when it's done.
|
||||
* Because we called cpu.stepCPU() and not cpu.startCPU(), we must nudge the Computer's update code,
|
||||
* and then update our own state. Normally, the only time fUpdateStatus will be false is when doTrace()
|
||||
* is calling us in a loop, in which case it will perform its own updateStatus() when it's done.
|
||||
*/
|
||||
if (fUpdateCPU !== false) this.cpu.updateCPU();
|
||||
if (fUpdateStatus !== false) this.cmp.updateStatus();
|
||||
|
||||
this.updateStatus(fRegs || false);
|
||||
return (this.nCycles > 0);
|
||||
|
|
@ -2550,7 +2550,7 @@ if (DEBUGGER) {
|
|||
if (asArgs[2] === undefined) {
|
||||
this.println("begin assemble at " + this.toStrAddr(dbgAddr));
|
||||
this.fAssemble = true;
|
||||
this.cpu.updateCPU();
|
||||
this.cmp.updateStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3247,7 +3247,7 @@ if (DEBUGGER) {
|
|||
this.println("unknown register: " + sReg);
|
||||
return;
|
||||
}
|
||||
cpu.updateCPU();
|
||||
this.cmp.updateStatus();
|
||||
this.println("updated registers:");
|
||||
}
|
||||
|
||||
|
|
@ -3493,11 +3493,12 @@ if (DEBUGGER) {
|
|||
},
|
||||
function onCountStepComplete() {
|
||||
/*
|
||||
* We explicitly called stepCPU() with fUpdateCPU === false, because repeatedly
|
||||
* calling updateCPU() can be very slow, especially when fDisplayLiveRegs is true,
|
||||
* so once the repeat count has been exhausted, we must perform a final updateCPU().
|
||||
* We explicitly called stepCPU() with fUpdateStatus === false, because repeatedly
|
||||
* calling updateStatus() can be very slow, especially if a Control Panel is present
|
||||
* with displayLiveRegs enabled, so once the repeat count has been exhausted, we must
|
||||
* perform a final updateStatus().
|
||||
*/
|
||||
dbg.cpu.updateCPU();
|
||||
dbg.cmp.updateStatus();
|
||||
dbg.setBusy(false);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -60,16 +60,16 @@ Component.subclass(KeyboardPDP11);
|
|||
KeyboardPDP11.MINPRESSTIME = 100; // 100ms
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {KeyboardPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "esc")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
KeyboardPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
KeyboardPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,30 +54,70 @@ 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.
|
||||
*/
|
||||
this.cLiveRegs = 0;
|
||||
/*
|
||||
* TODO: Add some UI for displayLiveRegs (either an XML property, or a UI checkbox, or both)
|
||||
*/
|
||||
this.flags.displayLiveRegs = true;
|
||||
|
||||
}
|
||||
|
||||
Component.subclass(PanelPDP11);
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* Most panel layouts don't have bindings of their own, so we pass along all binding requests to the
|
||||
* Computer, CPU, Keyboard and Debugger components first. The order shouldn't matter, since any component
|
||||
* that doesn't recognize the specified binding should simply ignore it.
|
||||
* Some panel layouts don't have bindings of their own, and even when they do, there may still be some
|
||||
* components (eg, the CPU) that prefer to update their own bindings, so we pass along all binding requests
|
||||
* to the Computer, CPU, Keyboard and Debugger components first. The order shouldn't matter, since any
|
||||
* component that doesn't recognize the specified binding should simply ignore it.
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
PanelPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
PanelPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
if (this.cmp && this.cmp.setBinding(sHTMLType, sBinding, control, sValue)) return true;
|
||||
if (this.cpu && this.cpu.setBinding(sHTMLType, sBinding, control, sValue)) return true;
|
||||
if (DEBUGGER && this.dbg && this.dbg.setBinding(sHTMLType, sBinding, control, sValue)) return true;
|
||||
return this.parent.setBinding.call(this, sHTMLType, sBinding, control, sValue);
|
||||
if (this.cmp && this.cmp.setBinding(sType, sBinding, control, sValue)) {
|
||||
return true;
|
||||
}
|
||||
if (this.cpu && this.cpu.setBinding(sType, sBinding, control, sValue)) {
|
||||
return true;
|
||||
}
|
||||
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":
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
return true;
|
||||
default:
|
||||
if (sType == "rled") {
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
return true;
|
||||
}
|
||||
return this.parent.setBinding.call(this, sType, sBinding, control, sValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -124,21 +164,98 @@ PanelPDP11.prototype.powerDown = function(fSave, fShutdown)
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateValue(sLabel, nValue, cch)
|
||||
*
|
||||
* This is principally for displaying register values, but in reality, it can be used to display any
|
||||
* numeric value bound to the given label.
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sLabel
|
||||
* @param {number} nValue
|
||||
* @param {number} [cch]
|
||||
*/
|
||||
PanelPDP11.prototype.updateValue = function(sLabel, nValue, cch)
|
||||
{
|
||||
if (this.bindings[sLabel]) {
|
||||
if (nValue === undefined) {
|
||||
this.setError("Value for " + sLabel + " is invalid");
|
||||
this.cpu.stopCPU();
|
||||
}
|
||||
var sVal;
|
||||
var nBase = this.dbg && this.dbg.nBase || 8;
|
||||
if (!this.cpu.isRunning() || this.flags.displayLiveRegs) {
|
||||
sVal = nBase == 8? str.toOct(nValue, cch) : str.toHex(nValue, cch);
|
||||
} else {
|
||||
sVal = "--------".substr(0, cch || 4);
|
||||
}
|
||||
/*
|
||||
* TODO: Determine if this test actually avoids any redrawing when a register hasn't changed, and/or if
|
||||
* we should maintain our own (numeric) cache of displayed register values (to avoid creating these temporary
|
||||
* string values that will have to garbage-collected), and/or if this is actually slower, and/or if I'm being
|
||||
* too obsessive.
|
||||
*/
|
||||
if (this.bindings[sLabel].textContent != sVal) this.bindings[sLabel].textContent = sVal;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setLED(control, f)
|
||||
*
|
||||
* @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"
|
||||
*/
|
||||
PanelPDP11.prototype.setLED = function(control, f)
|
||||
{
|
||||
/*
|
||||
* TODO: Add support for user-definable LED colors
|
||||
*/
|
||||
control.style.backgroundColor = (f? "#ff0000" : "#000000");
|
||||
};
|
||||
|
||||
/**
|
||||
* updateLEDs(sPrefix, data, nLEDs)
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {string} sPrefix
|
||||
* @param {number} data
|
||||
* @param {number} nLEDs
|
||||
*/
|
||||
PanelPDP11.prototype.updateLEDs = 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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus(fForce)
|
||||
*
|
||||
* Update function for Panels containing elements with high-frequency display requirements.
|
||||
*
|
||||
* For older (and slower) DOM-based display elements, those are sill being managed by the CPUState component,
|
||||
* so it has its own updateStatus() handler.
|
||||
*
|
||||
* The Computer's updateStatus() handler is currently responsible for calling both our handler and the CPU's handler.
|
||||
*
|
||||
* @this {PanelPDP11}
|
||||
* @param {boolean} [fForce] (true will display registers even if the CPU is running and "live" registers are not enabled)
|
||||
*/
|
||||
PanelPDP11.prototype.updateStatus = function(fForce)
|
||||
{
|
||||
if (this.cLiveRegs) {
|
||||
if (fForce || !this.cpu.isRunning() || this.flags.displayLiveRegs) {
|
||||
for (var i = 0; i < this.cpu.regsGen.length; i++) {
|
||||
this.updateValue('R'+i, this.cpu.regsGen[i]);
|
||||
}
|
||||
var regPSW = this.cpu.getPSW();
|
||||
this.updateValue("PS", regPSW);
|
||||
this.updateValue("NF", (regPSW & PDP11.PSW.NF)? 1 : 0, 1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -165,16 +165,16 @@ Component.subclass(SerialPortPDP11);
|
|||
SerialPortPDP11.sIOBuffer = "buffer";
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
* setBinding(sType, sBinding, control, sValue)
|
||||
*
|
||||
* @this {SerialPortPDP11}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string|null} sType is the type of the HTML control (eg, "button", "textarea", "register", "flag", "rled", etc)
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "buffer")
|
||||
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
|
||||
* @param {string} [sValue] optional data value
|
||||
* @return {boolean} true if binding was successful, false if unrecognized binding request
|
||||
*/
|
||||
SerialPortPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
SerialPortPDP11.prototype.setBinding = function(sType, sBinding, control, sValue)
|
||||
{
|
||||
var serial = this;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue