Added support for machine command links to assist in the creation of online tutorials; however, the commandMachine() function isn't wired to anything yet, and this only works with the Node web server (updating the Jekyll environment is next)
This commit is contained in:
parent
0eccf30d3c
commit
6f36583704
5 changed files with 106 additions and 43 deletions
|
|
@ -64,10 +64,10 @@ was add the following Front Matter to the top of the Markdown file:
|
||||||
|
|
||||||
and then embed the machines in the post, each with a single line:
|
and then embed the machines in the post, each with a single line:
|
||||||
|
|
||||||
{% raw %}
|
{% raw %}
|
||||||
{% include machine.html id="ibm5170" %}
|
{% include machine.html id="ibm5170" %}
|
||||||
{% include machine.html id="vt100" %}
|
{% include machine.html id="vt100" %}
|
||||||
{% endraw %}
|
{% endraw %}
|
||||||
|
|
||||||
For people rolling their own web pages, [the basics](/docs/pcx86/) haven't changed, and adding a serial connection merely
|
For people rolling their own web pages, [the basics](/docs/pcx86/) haven't changed, and adding a serial connection merely
|
||||||
requires adding a *connection* property (eg, `connection:"com2->vt100.serialPort"`) to the *parms* parameter passed to the
|
requires adding a *connection* property (eg, `connection:"com2->vt100.serialPort"`) to the *parms* parameter passed to the
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ beginning of the PDP-11 line: the PDP-11/20.
|
||||||
I'm starting with the top-of-the-line PDP-11/70 largely because the core of the emulator is being adapted from the
|
I'm starting with the top-of-the-line PDP-11/70 largely because the core of the emulator is being adapted from the
|
||||||
JavaScript [PDP-11/70 Emulator (v1.3)](http://skn.noip.me/pdp11/pdp11.html) written by
|
JavaScript [PDP-11/70 Emulator (v1.3)](http://skn.noip.me/pdp11/pdp11.html) written by
|
||||||
Paul Nankervis, who has generously given permission to use his code in PCjs. Since his emulator is a fully functional
|
Paul Nankervis, who has generously given permission to use his code in PCjs. Since his emulator is a fully functional
|
||||||
11/70, it made sense to start there and work backwards, factoring out features as needed.
|
11/70, it made sense to start there and work backwards, disabling features according to the model.
|
||||||
|
|
||||||
The code has already undergone a lot of refactoring. Opcodes are now decoded by function tables rather than a single
|
The code has already undergone a lot of refactoring. Opcodes are now decoded by function tables rather than a single
|
||||||
switch statement, and every opcode is implemented with a discrete function. Other refactoring includes flag management,
|
switch statement, and every opcode is implemented with a discrete function. Other refactoring includes flag management,
|
||||||
interrupt management, and device management.
|
interrupt management, and device management.
|
||||||
|
|
||||||
|
|
@ -37,9 +37,9 @@ component, [device.js](/modules/pdp11/lib/device.js), which has now been convert
|
||||||
|
|
||||||
The first new device component is [serial.js](/modules/pdp11/lib/serial.js), which is currently the
|
The first new device component is [serial.js](/modules/pdp11/lib/serial.js), which is currently the
|
||||||
only means PDPjs has of communicating with the outside world. So you can try
|
only means PDPjs has of communicating with the outside world. So you can try
|
||||||
[PDPjs connected to a VT100 Terminal](/devices/pdp11/machine/1170/vt100/), by clicking the **Run** button on the test machine.
|
[PDPjs connected to a VT100 Terminal](/devices/pdp11/machine/1170/vt100/), by clicking the **Run** button on the
|
||||||
The test machine is running [custom boot code](/apps/pdp11/boot/test/), adapted from boot code written by Paul, but due to the
|
test machine. The test machine is running a custom [Boot Monitor](/apps/pdp11/boot/monitor/) included with
|
||||||
lack of other device support, nothing can be booted yet.
|
[Paul's emulator](http://skn.noip.me/pdp11/), but due to the lack of other device support, nothing can be booted yet.
|
||||||
|
|
||||||
Obviously PDPjs is very much a work-in-progress. Before I proceed much farther, I really want to put the CPU through
|
Obviously PDPjs is very much a work-in-progress. Before I proceed much farther, I really want to put the CPU through
|
||||||
some rigorous testing, so I'll be on the lookout for some comprehensive PDP-11 instruction tests. Or I'll write my own,
|
some rigorous testing, so I'll be on the lookout for some comprehensive PDP-11 instruction tests. Or I'll write my own,
|
||||||
|
|
|
||||||
|
|
@ -16,39 +16,44 @@ machines:
|
||||||
sticky: top
|
sticky: top
|
||||||
---
|
---
|
||||||
|
|
||||||
Introducing PDP-11 tutorials!
|
Introducing PDP-11 tutorials. For more information, keep scrolling.
|
||||||
|
|
||||||
{% include machine.html id="vt100" %}
|
{% include machine.html id="vt100" %}
|
||||||
|
|
||||||
[PDPjs](/devices/pdp11/machine/) is the newest addition to the PCjs family of emulators, joining PCx86, PC8080, and C1Pjs.
|
[PDPjs](/devices/pdp11/machine/) is able to run a variety of old DEC operating systems, such as RT-11 and RSTS/E,
|
||||||
|
and while there are manuals available online, thanks to the efforts of those who operate and contribute to websites
|
||||||
|
like [bitsavers.org](http://bitsavers.org), I suspect most people don't have a lot of interest or time to spend
|
||||||
|
reading old manuals.
|
||||||
|
|
||||||
While PDPjs may eventually support a range of DEC PDP machines, my current focus is on the PDP-11, starting with the
|
In an effort to remedy that situation, I'm adding some new features to PCjs. The first feature is what I call
|
||||||
PDP-11/70. From there, I'll work backwards to support other PDP-11 models, such as the PDP-11/45, until I reach the
|
"Sticky Machines", and it's more a website feature than a machine feature. At the top of any PCjs webpage, in the
|
||||||
beginning of the PDP-11 line: the PDP-11/20.
|
*machines* section, a machine can now have a *sticky* property. For now, the only supported value is "top"; e.g.:
|
||||||
|
|
||||||
I'm starting with the top-of-the-line PDP-11/70 largely because the core of the emulator is being adapted from the
|
machines:
|
||||||
JavaScript [PDP-11/70 Emulator (v1.3)](http://skn.noip.me/pdp11/pdp11.html) written by
|
- id: vt100
|
||||||
Paul Nankervis, who has generously given permission to use his code in PCjs. Since his emulator is a fully functional
|
type: pc8080
|
||||||
11/70, it made sense to start there and work backwards, factoring out features as needed.
|
config: /devices/pc8080/machine/vt100/machine.xml
|
||||||
|
connection: serialPort->test1170.dl11
|
||||||
|
sticky: top
|
||||||
|
|
||||||
The code has already undergone a lot of refactoring. Opcodes are now decoded by function tables rather than a single
|
A sticky machine makes it easier to construct a tutorial page for a single machine, by preventing that machine from
|
||||||
switch statement, and every opcode is implemented with a discrete function. Other refactoring includes flag management,
|
scrolling off the top of the page; it "sticks" to the top instead. The rest of the page scrolls normally, allowing the
|
||||||
interrupt management, and device management.
|
user to progress at their own pace through the text and/or images of an accompanying tutorial.
|
||||||
|
|
||||||
Most of the work remaining is in device management. Like other PCjs emulators, PDPjs has a Bus component,
|
The second feature is a generalized method for sending commands to components within a machine. For example, if we
|
||||||
[bus.js](/modules/pdp11/lib/bus.js), that allows separate device components to register I/O handlers for specific
|
want to send some keyboard commands to machine:
|
||||||
UNIBUS addresses. During the initial port, I moved all of Paul's original device management code into one "catch-all"
|
|
||||||
component, [device.js](/modules/pdp11/lib/device.js), which has now been converted to the new I/O registration model.
|
|
||||||
|
|
||||||
The first new device component is [serial.js](/modules/pdp11/lib/serial.js), which is currently the
|
{% raw %}
|
||||||
only means PDPjs has of communicating with the outside world. So you can try
|
{% include machine-command.html type='button' label='Try It!' machine='vt100' component='Keyboard' command='sendString' value='Hello World' %}
|
||||||
[PDPjs connected to a VT100 Terminal](/devices/pdp11/machine/1170/vt100/), by clicking the **Run** button on the test machine.
|
{% endraw %}
|
||||||
The test machine is running [custom boot code](/apps/pdp11/boot/test/), adapted from boot code written by Paul, but due to the
|
|
||||||
lack of other device support, nothing can be booted yet.
|
|
||||||
|
|
||||||
Obviously PDPjs is very much a work-in-progress. Before I proceed much farther, I really want to put the CPU through
|
which should translate into a control that looks like:
|
||||||
some rigorous testing, so I'll be on the lookout for some comprehensive PDP-11 instruction tests. Or I'll write my own,
|
|
||||||
and compare results across 1 or 2 other PDP-11 emulators.
|
<button type="button" onclick="commandMachine('vt100','Keyboard','sendString','Hello World')">Try It!</button>
|
||||||
|
|
||||||
|
In fact, let's try it now. {% include machine-command.html type='button' label='Try It!' machine='vt100' component='Keyboard' command='sendString' value='Hello World' %}
|
||||||
|
|
||||||
|
Obviously, every component we want to control will need to be updated to export the necessary functions.
|
||||||
|
|
||||||
{% include machine.html id="test1170" %}
|
{% include machine.html id="test1170" %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -942,10 +942,12 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
|
||||||
* Before we start replacing Markdown links, see if there are any Liquid-style replacements
|
* Before we start replacing Markdown links, see if there are any Liquid-style replacements
|
||||||
* (in case this Markdown file is part of a Jekyll installation) and remove them.
|
* (in case this Markdown file is part of a Jekyll installation) and remove them.
|
||||||
*
|
*
|
||||||
* TODO: These replacements should use appropriate values from _config.yml; however, unless/until
|
* TODO: Any double-brace replacements should use appropriate values from _config.yml or the
|
||||||
* we start using Node again to host the public site, that's low priority.
|
* page's Front Matter; however, unless/until we start using Node again to host the public site,
|
||||||
|
* that's low priority.
|
||||||
*/
|
*/
|
||||||
sBlock = sBlock.replace(/\{([\{%]).*?\1}/g, "");
|
sBlock = sBlock.replace(/([^\t])\{([\{%]).*?\2}/g, "$1");
|
||||||
|
sBlock = sBlock.replace(/(\{)([\{%])(.*?\2})/g, "<pre><code>$1$2$3</code></pre>");
|
||||||
|
|
||||||
var aMatch;
|
var aMatch;
|
||||||
var re = /\[([^\[\]]*)]\((.*?)(?:\s*"(.*?)"\)|\))/g;
|
var re = /\[([^\[\]]*)]\((.*?)(?:\s*"(.*?)"\)|\))/g;
|
||||||
|
|
@ -1150,21 +1152,21 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
|
||||||
*/
|
*/
|
||||||
MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
||||||
{
|
{
|
||||||
var aMatch, sReplacement;
|
var aMatch, sReplacement, machine;
|
||||||
var sMachineType, sMachineID, sMachineXMLFile, sMachineXSLFile, sMachineVersion, sMachineOptions, sMachineParms;
|
var sMachineType, sMachineID, sMachineXMLFile, sMachineXSLFile, sMachineVersion, sMachineOptions, sMachineParms;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before we start looking for Markdown-style machine links, see if there are any Liquid-style machines,
|
* Before we start looking for Markdown-style machine links, see if there are any Liquid-style machines,
|
||||||
* (in case this Markdown file is part of a Jekyll installation) and convert them to Markdown-style links.
|
* (in case this Markdown file is part of a Jekyll installation) and convert them to Markdown-style links.
|
||||||
*/
|
*/
|
||||||
|
var reIncludes = /(.){%\s*include\s+machine\.html\s+id=(["'])(.*?)\2\s*%}/g;
|
||||||
var reIncludes = /\{%\s*include\s+machine\.html\s+id=(["'])(.*?)\1\s*%}/g;
|
|
||||||
|
|
||||||
while ((aMatch = reIncludes.exec(sBlock))) {
|
while ((aMatch = reIncludes.exec(sBlock))) {
|
||||||
|
if (aMatch[1] == '\t') continue;
|
||||||
sReplacement = "";
|
sReplacement = "";
|
||||||
sMachineID = aMatch[2];
|
sMachineID = aMatch[3];
|
||||||
if (this.aMachineDefs[sMachineID]) {
|
if (this.aMachineDefs[sMachineID]) {
|
||||||
var machine = this.aMachineDefs[sMachineID];
|
machine = this.aMachineDefs[sMachineID];
|
||||||
sMachineType = machine['type'] || "PCx86";
|
sMachineType = machine['type'] || "PCx86";
|
||||||
sMachineOptions = ((sMachineType.indexOf("-dbg") > 0 || machine['debugger'] == "true")? "debugger" : "");
|
sMachineOptions = ((sMachineType.indexOf("-dbg") > 0 || machine['debugger'] == "true")? "debugger" : "");
|
||||||
if (machine['sticky']) sMachineOptions += (sMachineOptions? "," : "") + "sticky";
|
if (machine['sticky']) sMachineOptions += (sMachineOptions? "," : "") + "sticky";
|
||||||
|
|
@ -1176,11 +1178,14 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
||||||
sReplacement = machine['name'] || "Embedded PC";
|
sReplacement = machine['name'] || "Embedded PC";
|
||||||
sReplacement = "[" + sReplacement + "](" + sMachineXMLFile + ' "' + sMachineType + '!' + sMachineID + '!' + sMachineXSLFile + '!!' + sMachineOptions + '!' + sMachineParms + '")';
|
sReplacement = "[" + sReplacement + "](" + sMachineXMLFile + ' "' + sMachineType + '!' + sMachineID + '!' + sMachineXSLFile + '!!' + sMachineOptions + '!' + sMachineParms + '")';
|
||||||
}
|
}
|
||||||
sBlock = sBlock.replace(aMatch[0], sReplacement);
|
sBlock = sBlock.replace(aMatch[0].substr(1), sReplacement);
|
||||||
reIncludes.lastIndex = 0; // reset lastIndex, since we just modified the string that reIncludes is iterating over
|
reIncludes.lastIndex = 0; // reset lastIndex, since we just modified the string that reIncludes is iterating over
|
||||||
}
|
}
|
||||||
|
|
||||||
sBlock = sBlock.replace(/\{%\s*include\s+build\.html\s+id=(["'])(.*?)\1\s*%}/g, '<div class="buildpc" id=$1$2$1></div>');
|
/*
|
||||||
|
* Ditto for any Liquid-style machine build links.
|
||||||
|
*/
|
||||||
|
sBlock = sBlock.replace(/\{%\s*include\s+machine-build\.html\s+id=(["'])(.*?)\1\s*%}/g, '<div class="buildpc" id=$1$2$1></div>');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start looking for Markdown-style machine links now...
|
* Start looking for Markdown-style machine links now...
|
||||||
|
|
@ -1254,6 +1259,43 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Last but not least, see if there are any Liquid-style machine command links that need to be converted.
|
||||||
|
*/
|
||||||
|
reIncludes = /([ \t]*)\{%\s*include\s+machine-command\.html\s+(.*?)\s*%}/g;
|
||||||
|
|
||||||
|
var findParm = function(aParms, sParm) {
|
||||||
|
sParm += '=';
|
||||||
|
for (var i = 0; i < aParms.length; i++) {
|
||||||
|
if (aParms[i].indexOf(sParm) == 0) {
|
||||||
|
return aParms[i].slice(sParm.length+1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((aMatch = reIncludes.exec(sBlock))) {
|
||||||
|
if (aMatch[1] == '\t') continue;
|
||||||
|
var aParms = aMatch[2].match(/[a-z]+=(["']).*?\1/g);
|
||||||
|
if (!aParms) continue;
|
||||||
|
sReplacement = "";
|
||||||
|
sMachineID = findParm(aParms, 'machine');
|
||||||
|
var sControl = findParm(aParms, 'type') || 'button';
|
||||||
|
var sControlType = sControl == 'button'? ' type="button"' : '';
|
||||||
|
if (this.aMachineDefs[sMachineID]) {
|
||||||
|
sReplacement = '<' + sControl + sControlType + ' onclick="commandMachine(';
|
||||||
|
sReplacement += "'" + sMachineID + "',";
|
||||||
|
sReplacement += "'" + findParm(aParms, 'component') + "',";
|
||||||
|
sReplacement += "'" + findParm(aParms, 'command') + "',";
|
||||||
|
sReplacement += "'" + findParm(aParms, 'value') + "')";
|
||||||
|
sReplacement += '">' + (findParm(aParms, 'label') || 'Try It!') + '</' + sControl + '>';
|
||||||
|
} else {
|
||||||
|
sReplacement = "<!-- Unrecognized machine ID: " + sMachineID + " -->";
|
||||||
|
}
|
||||||
|
sBlock = sBlock.replace(aMatch[0], sReplacement);
|
||||||
|
reIncludes.lastIndex = 0; // reset lastIndex, since we just modified the string that reIncludes is iterating over
|
||||||
|
}
|
||||||
|
|
||||||
if (cMatches) {
|
if (cMatches) {
|
||||||
sBlock = sBlock.replace(/^<p>([\s\S]*)<\/p>$/g, "$1");
|
sBlock = sBlock.replace(/^<p>([\s\S]*)<\/p>$/g, "$1");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addStickYMachine(idMachine)
|
* addStickyMachine(idMachine)
|
||||||
*
|
*
|
||||||
* @param {string} idMachine
|
* @param {string} idMachine
|
||||||
*/
|
*/
|
||||||
|
|
@ -41,7 +41,10 @@ function addStickyMachine(idMachine)
|
||||||
/*
|
/*
|
||||||
* TODO: Determine if/when we can cache the machine and machineSibling elements; we already
|
* TODO: Determine if/when we can cache the machine and machineSibling elements; we already
|
||||||
* know we can't cache them when addStickyMachine() is first called, because that currently
|
* know we can't cache them when addStickyMachine() is first called, because that currently
|
||||||
* happens *before* embed.js replaces the placeholder machine DIV with the *real* machine DIV.
|
* happens before embed.js replaces the placeholder machine <div> with the real machine <div>.
|
||||||
|
*
|
||||||
|
* Placement of the addStickyMachine() call is irrelevant, because embed.js asynchronously
|
||||||
|
* reads all the XML files that define the machine *before* replacing the <div>.
|
||||||
*/
|
*/
|
||||||
var machine = document.getElementById(idMachine);
|
var machine = document.getElementById(idMachine);
|
||||||
if (machine) {
|
if (machine) {
|
||||||
|
|
@ -70,6 +73,19 @@ function addStickyMachine(idMachine)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* commandMachine(idMachine, typeComponent, sCommand, sValue)
|
||||||
|
*
|
||||||
|
* @param {string} idMachine
|
||||||
|
* @param {string} typeComponent
|
||||||
|
* @param {string} sCommand
|
||||||
|
* @param {string} [sValue]
|
||||||
|
*/
|
||||||
|
function commandMachine(idMachine, typeComponent, sCommand, sValue)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* findTop(obj)
|
* findTop(obj)
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue