layout | title | permalink |
---|---|---|
page |
PCjs Device Classes |
/modules/devices/ |
In the spirit of Vanilla JS, a new and improved set of ES2015 (ES6) JavaScript classes are being used to create a variety of newer (late 2017) PCjs Machines.
These machines are constructed from one or more "Device" classes:
along with one of the following "CPU" classes:
- 8080 CPU (with 8080 Debugger and Debugger Services)
- LED Controller "CPU"
- TMS-1500 Calculator CPU (with built-in "mini-debugger")
a "Machine" class that manages the entire machine:
an assortment of classes for machine-specific hardware, such as:
all of which, in turn, are built upon a simple set of library classes:
Examples of those newer PCjs Machines include:
- Texas Instruments TI-42, TI-55, and TI-57 Programmable Calculators
- John Conway's "Game of Life" Cellular Automaton built as an LED Simulation
- Hasbro's "Lite-Brite" reimagined as an LED Simulation (eg, Animated Christmas Tree)
- LED Scroller and LED Symbol Builder
On the PCjs website, Jekyll Front Matter and templates are used define and embed complete machines.
The Markdown file
in the TI-57 directory provides a good example. The Front Matter at the top of the file
is where you define one or more machines
, each with the following minimum set of properties:
machines:
- id: ti57
type: ti57
name: TI-57 Programmable Calculator
config: /devices/ti57/machine/rev0/ti57.json
The config
property specifies the location of a JSON configuration file that
describes the machine's internal devices, the IDs of any visual controls that they bind to, and any resources they require (e.g.,
ROM contents).
Alternatively, a JSON configuration blob can be embedded directly in the machine definition:
config: |
{
"ti57": {
"class": "Machine",
"type": "TI57",
"name": "TI-57 Emulator",
"bindings": {
"clear": "clearTI57",
"print": "printTI57"
}
},
"cpu": {
"class": "CPU1500",
"type": "TMS-1500"
},
"clock": {
"class": "Time",
"cyclesPerSecond": 650000,
"bindings": {
"run": "runTI57",
"speed": "speedTI57",
"step": "stepTI57"
}
},
"display": {
"class": "LED",
"type": 3,
"cols": 12,
"rows": 1,
"color": "red",
"backgroundColor": "black",
"bindings": {
"container": "displayTI57"
}
},
"input": {
"class": "Input",
"location": [139, 325, 368, 478, 0.34, 0.5, 640, 853, 418, 180, 75, 36],
"map": [
["2nd", "inv", "lnx", "\\b", "clr"],
["lrn", "xchg", "sq", "sqrt", "rcp"],
["sst", "sto", "rcl", "sum", "exp"],
["bst", "ee", "(", ")", "/"],
["gto", "7", "8", "9", "*"],
["sbr", "4", "5", "6", "-"],
["rst", "1", "2", "3", "+"],
["r/s", "0", ".", "+/-", "=|\\r"]
],
"bindings": {
"surface": "imageTI57",
"power": "powerTI57",
"reset": "resetTI57"
}
},
"rom": {
"class": "ROM",
"wordSize": 13,
"valueSize": 16,
"valueTotal": 2048,
"littleEndian": true,
"file": "ti57le.bin",
"reference": "",
"values": [
4623,4386,5106,7051,3246,6152,5813,5628,5805,7051,4386,3246,7911,5132,1822,6798,
...
8183,1313,8182,613,3343,7148,39,3188,6561,3130,3090,7165,3188,3587,0,0
]
}
}
Front Matter also provides a convenient way to define styles for any of the visual controls.
The syntax is similar to basic CSS, except that identifiers with a leading underscore correspond to control
IDs without the underscore (in CSS, you would use #
in front of each identifier, but that's a comment
character in Front Matter). You can also define style classes, by using identifiers with a leading period.
styles:
_ti57:
position: relative;
display: inline-block;
_displayTI57:
position: absolute;
left: 16%;
top: 7%;
width: 70%;
height: 4%;
Next, add some HTML markup at the desired page location, such as:
<div id="ti57">
<img id="imageTI57" src="/devices/ti57/images/ti57.png"/>
<div id="displayTI57"></div>
<button id="powerTI57">Power</button>
</div>
<div style="float:left;">
<div style="width:100%;">
<p>Diagnostics</p>
<textarea id="printTI57" cols="78" rows="16"></textarea>
</div>
<button id="runTI57">Run</button>
<button id="stepTI57">Step</button><span id="speedTI57">Stopped</span>
<button id="resetTI57">Reset</button>
<button id="clearTI57">Clear</button>
</div>
Finally, you embed the machine with a simple include template:
{% include machine.html id="ti57" %}
which automatically adds all the necessary scripts, as listed in machines.json:
<script src="/modules/devices/lib/defs.js"></script>
<script src="/modules/devices/lib/numio.js"></script>
<script src="/modules/devices/lib/stdio.js"></script>
<script src="/modules/devices/lib/webio.js"></script>
<script src="/modules/devices/main/device.js"></script>
<script src="/modules/devices/main/input.js"></script>
<script src="/modules/devices/main/led.js"></script>
<script src="/modules/devices/main/time.js"></script>
<script src="/modules/devices/bus/bus.js"></script>
<script src="/modules/devices/bus/memory.js"></script>
<script src="/modules/devices/bus/rom.js"></script>
<script src="/modules/devices/cpu/cpu.js"></script>
<script src="/modules/devices/cpu/cpu1500.js"></script>
<script src="/modules/devices/main/machine.js"></script>
and then creates the machine using the factory name (eg, "TMS1500") specified in machines.json:
TMS1500('ti57','{JSON blob}');
or, if an external JSON file is used, with:
TMS1500('ti57,'/devices/ti57/machine/rev0/ti57.json');
Of course, you can add any or all of those lines yourself if you don't want to use the include template.