Scriptable machine improvements (including support for sleep)
This commit is contained in:
parent
033f0bf212
commit
112c0e88c6
55 changed files with 15397 additions and 1381 deletions
|
|
@ -229,29 +229,19 @@ class SerialPort8080 extends Component {
|
|||
this.bindings[sBinding] = control;
|
||||
|
||||
/*
|
||||
* Backslash sequences like \n, \r and \\ have already been converted to LF, CR and backslash
|
||||
* Backslash sequences like \n, \r, and \\ have already been converted to LF, CR and backslash
|
||||
* characters, by virtue of the eval() function that all our component parameter strings pass through;
|
||||
* eval() treats strings like "source code", so any backslash sequence that JavaScript supports is
|
||||
* automatically converted.
|
||||
*
|
||||
* The complete list of supported backslash sequences:
|
||||
* The complete list of backslash sequences supported by JavaScript:
|
||||
*
|
||||
* \0 \' \" \\ \n \r \v \t \b \f \uXXXX \xXX
|
||||
* ^J ^M ^K ^I ^H ^L
|
||||
*
|
||||
* We also want to support some additional sequences, like backslash-e for ESC. Only one problem: for
|
||||
* any unrecognized backslash sequence, eval() simply removes the backslash. So we have to double-backslash
|
||||
* it, which eval() will replace with a single backslash.
|
||||
*
|
||||
* So, additional supported backslash sequences include:
|
||||
*
|
||||
* \\e (ESC)
|
||||
*
|
||||
* Note that I've judiciously avoided using terms "escape notation" or "escape sequence" to talk about
|
||||
* these sequences, because ESC is one of the additional characters I want to support, and using the word
|
||||
* "escape" in both contexts is WAY too confusing.
|
||||
* To support any other non-printable 8-bit character, such as ESC, you should use \xXX, where XX
|
||||
* is the ASCII code in hex. For ESC, that would \x1B.
|
||||
*/
|
||||
sValue = sValue.replace(/\\e/g, String.fromCharCode(0x1b));
|
||||
|
||||
control.onclick = function onClickTest(event) {
|
||||
serial.receiveData(sValue);
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -961,6 +961,7 @@ class ComputerPDP11 extends Component {
|
|||
*/
|
||||
reset()
|
||||
{
|
||||
this.flags.reset = true;
|
||||
if (this.bus && this.bus.reset) {
|
||||
this.printMessage("Resetting " + this.bus.type);
|
||||
this.bus.reset();
|
||||
|
|
@ -977,6 +978,7 @@ class ComputerPDP11 extends Component {
|
|||
component.reset();
|
||||
}
|
||||
}
|
||||
this.flags.reset = false;
|
||||
this.updateDisplays(-1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -588,13 +588,11 @@ class CPUStatePDP11 extends CPUPDP11 {
|
|||
this.regsGen[0] = bUnit || 0;
|
||||
for (var i = 1; i <= 5; i++) this.regsGen[i] = 0;
|
||||
this.regsGen[6] = addrStack || 0o2000;
|
||||
if (!this.dbg) {
|
||||
if (!this.flags.powered) {
|
||||
this.flags.autoStart = true;
|
||||
}
|
||||
else if (!this.flags.running) {
|
||||
this.startCPU();
|
||||
}
|
||||
if (!this.flags.powered) {
|
||||
this.flags.autoStart = true;
|
||||
}
|
||||
else if (!this.flags.running) {
|
||||
this.startCPU();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -608,7 +606,7 @@ class CPUStatePDP11 extends CPUPDP11 {
|
|||
* we should probably force a complete reset, but for now, it's up to the user to hit the reset button
|
||||
* themselves.
|
||||
*/
|
||||
if (!this.stopCPU()) {
|
||||
if (!this.stopCPU() && !this.cmp.flags.reset) {
|
||||
this.dbg.updateStatus();
|
||||
this.cmp.updateDisplays(-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ class DriveController extends Component {
|
|||
this.irq = null;
|
||||
|
||||
this['exports'] = {
|
||||
'boot': this.bootSelectedDisk,
|
||||
'load': this.loadSelectedDrive,
|
||||
'bootDisk': this.bootSelectedDisk,
|
||||
'loadDisk': this.loadSelectedDrive,
|
||||
'selectDrive': this.selectDrive,
|
||||
'wait': this.waitDrives,
|
||||
};
|
||||
|
|
@ -1133,19 +1133,17 @@ class DriveController extends Component {
|
|||
*
|
||||
* @this {DriveController}
|
||||
* @param {function()|null} fnCallReady
|
||||
* @return {boolean} true if successful, false if not
|
||||
* @return {boolean} false if wait required, true otherwise
|
||||
*/
|
||||
waitDrives(fnCallReady)
|
||||
{
|
||||
for (var iDrive = 0; iDrive < this.aDrives.length; iDrive++) {
|
||||
var drive = this.aDrives[iDrive];
|
||||
if (drive && drive.fBusy) {
|
||||
drive.fnCallReady = fnCallReady;
|
||||
fnCallReady = null;
|
||||
break;
|
||||
if (!drive.fnCallReady) drive.fnCallReady = fnCallReady;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fnCallReady) fnCallReady();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ class RAMPDP11 extends Component {
|
|||
*/
|
||||
this.bus.zeroMemory(this.addrRAM, this.sizeRAM, 0);
|
||||
if (this.abInit) {
|
||||
this.loadImage(this.abInit, this.addrLoad, this.addrExec, this.addrRAM, true);
|
||||
this.loadImage(this.abInit, this.addrLoad, this.addrExec, this.addrRAM, !this.dbg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ class SerialPortPDP11 extends Component {
|
|||
{
|
||||
var fTransmitted = false;
|
||||
|
||||
this.printMessage("transmitByte(" + Str.toHexByte(b) + ")");
|
||||
if (MAXDEBUG) this.printMessage("transmitByte(" + Str.toHexByte(b) + ")");
|
||||
|
||||
if (this.sendData) {
|
||||
if (this.sendData.call(this.connection, b)) {
|
||||
|
|
|
|||
|
|
@ -621,6 +621,18 @@ class Component {
|
|||
/**
|
||||
* Component.getScriptCommands(sScript)
|
||||
*
|
||||
* Backslash sequences like \n, \r, and \\ have already been converted to LF, CR and backslash
|
||||
* characters, since the entire script string was injected into a JavaScript function call, so
|
||||
* any backslash sequence that JavaScript supports was automatically converted.
|
||||
*
|
||||
* The complete list of backslash sequences supported by JavaScript:
|
||||
*
|
||||
* \0 \' \" \\ \n \r \v \t \b \f \uXXXX \xXX
|
||||
* ^J ^M ^K ^I ^H ^L
|
||||
*
|
||||
* To support any other non-printable 8-bit character, such as ESC, you should use \xXX, where XX
|
||||
* is the ASCII code in hex. For ESC, that would \x1B.
|
||||
*
|
||||
* @param {string} sScript
|
||||
* @return {Array}
|
||||
*/
|
||||
|
|
@ -706,42 +718,71 @@ class Component {
|
|||
|
||||
var aTokens = aaCommands[iCommand];
|
||||
var sCommand = aTokens[0];
|
||||
var fnScript = Component.scriptCommands[sCommand];
|
||||
var component = Component.getComponentByType(aTokens[1], idMachine);
|
||||
|
||||
var fnCallReady = null;
|
||||
if (Component.asyncCommands.indexOf(sCommand) >= 0) {
|
||||
fnCallReady = function processNextCommand(iNextCommand) {
|
||||
return function() {
|
||||
Component.processCommands(idMachine, aaCommands, iNextCommand);
|
||||
}
|
||||
}(iCommand + 1);
|
||||
}
|
||||
|
||||
var fnScript = Component.globalCommands[sCommand];
|
||||
if (fnScript) {
|
||||
fSuccess = fnScript(component, aTokens[2], aTokens[3]);
|
||||
if (!fnCallReady) {
|
||||
fSuccess = fnScript(aTokens[1], aTokens[2], aTokens[3]);
|
||||
} else {
|
||||
if (!fnScript(fnCallReady, aTokens[1], aTokens[2], aTokens[3])) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fSuccess = false;
|
||||
var component = Component.getComponentByType(aTokens[1], idMachine);
|
||||
if (component) {
|
||||
var exports = component['exports'];
|
||||
if (exports) {
|
||||
var fnCommand = exports[sCommand];
|
||||
if (fnCommand) {
|
||||
if (sCommand == "wait") {
|
||||
var fnCallReady = function processNextCommand(iNextCommand) {
|
||||
return function() {
|
||||
Component.processCommands(idMachine, aaCommands, iNextCommand);
|
||||
}
|
||||
}(iCommand + 1);
|
||||
fSuccess = fnCommand.call(component, fnCallReady);
|
||||
break;
|
||||
fnScript = Component.componentCommands[sCommand];
|
||||
if (fnScript) {
|
||||
fSuccess = fnScript(component, aTokens[2], aTokens[3]);
|
||||
}
|
||||
else {
|
||||
var exports = component['exports'];
|
||||
if (exports) {
|
||||
var fnCommand = exports[sCommand];
|
||||
if (fnCommand) {
|
||||
fSuccess = true;
|
||||
if (!fnCallReady) {
|
||||
fSuccess = fnCommand.call(component, aTokens[2], aTokens[3]);
|
||||
} else {
|
||||
if (!fnCommand.call(component, fnCallReady, aTokens[2], aTokens[3])) break;
|
||||
}
|
||||
}
|
||||
fSuccess = fnCommand.call(component, aTokens[2], aTokens[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fSuccess) {
|
||||
Component.alertUser("error processing script command (" + sCommand + ")");
|
||||
Component.alertUser("Script error (" + sCommand + ")");
|
||||
break;
|
||||
}
|
||||
|
||||
iCommand++;
|
||||
}
|
||||
return fSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component.scriptAlert(sMessage)
|
||||
*
|
||||
* @param {string} sMessage
|
||||
* @return {boolean}
|
||||
*/
|
||||
static scriptAlert(sMessage)
|
||||
{
|
||||
Component.alertUser(sMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component.scriptSelect(component, sBinding, sValue)
|
||||
*
|
||||
|
|
@ -753,24 +794,35 @@ class Component {
|
|||
static scriptSelect(component, sBinding, sValue)
|
||||
{
|
||||
var fSuccess = false;
|
||||
if (component) {
|
||||
var aBindings = component['bindings'];
|
||||
var control = aBindings[sBinding];
|
||||
if (control) {
|
||||
for (var i = 0; i < control.options.length; i++) {
|
||||
if (control.options[i].textContent == sValue) {
|
||||
if (control.selectedIndex != i) {
|
||||
control.selectedIndex = i;
|
||||
}
|
||||
fSuccess = true;
|
||||
break;
|
||||
var aBindings = component['bindings'];
|
||||
var control = aBindings[sBinding];
|
||||
if (control) {
|
||||
for (var i = 0; i < control.options.length; i++) {
|
||||
if (control.options[i].textContent == sValue) {
|
||||
if (control.selectedIndex != i) {
|
||||
control.selectedIndex = i;
|
||||
}
|
||||
fSuccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component.scriptSleep(fnCallback, sDelay)
|
||||
*
|
||||
* @param {function()} fnCallback
|
||||
* @param {string} sDelay (in milliseconds)
|
||||
* @return {boolean}
|
||||
*/
|
||||
static scriptSleep(fnCallback, sDelay)
|
||||
{
|
||||
setTimeout(fnCallback, +sDelay);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString()
|
||||
*
|
||||
|
|
@ -1223,7 +1275,14 @@ if (window) {
|
|||
Component.machines = window? window['PCjs']['Machines'] : {};
|
||||
Component.components = window? window['PCjs']['Components'] : [];
|
||||
|
||||
Component.scriptCommands = {
|
||||
Component.asyncCommands = [
|
||||
'sleep', 'wait'
|
||||
];
|
||||
Component.globalCommands = {
|
||||
'alert': Component.scriptAlert,
|
||||
'sleep': Component.scriptSleep
|
||||
};
|
||||
Component.componentCommands = {
|
||||
'select': Component.scriptSelect
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue