Numerous changes to make paper tape configurations more consistent with disk configurations. This allows all devices to share the machine-wide "autoMount" configuration object, now that the PC11 has a proper device name ("PTR"), making its properties distinguishable from those for RK11 and RL11 drives (eg, "RK0", "RL0", etc). And all the tape/disk components now use "Load" functions to connect a tape or disk to a device ("Attach" is deprecated). And finally, all tape/disk components now support operations to deposit their media directly into memory -- although in this case, the names of the operations are necessarily different: "Read" for tape images, "Boot" for disk images. The difference is partly historical convention but also reflects the fact that a "Boot" operation is more limited: paper tapes were designed to be completely loaded into memory, whereas bootable disks are designed for only the first sector to be loaded and executed. Also, paper tape images are now flagged as non-auto-starting, because they often require some user action (eg, loading another tape, setting some switches, etc), whereas disk boot sectors are flagged as auto-starting (see the fStart parameter of the loadImage() interface in the RAM component).

This commit is contained in:
Jeff Parsons 2016-12-03 14:49:51 -08:00 • committed by Jeff Parsons
commit b54253acf9
41 changed files with 383 additions and 211 deletions

View file

@ -21,12 +21,12 @@ component, including a new *loadImage()* interface that understands DEC's paper
To provide a more "authentic" experience, there is also a new [PC11 Paper Tape](/devices/pdp11/pc11/) component, To provide a more "authentic" experience, there is also a new [PC11 Paper Tape](/devices/pdp11/pc11/) component,
and machines can now be configured to include a virtual paper tape reader, with an [assortment of paper tapes](/apps/pdp11/tapes/) and machines can now be configured to include a virtual paper tape reader, with an [assortment of paper tapes](/apps/pdp11/tapes/)
ready to be attached. ready to be loaded.
In the real world, before you could load *any* paper tape, you had to first enter a In the real world, before you could load *any* paper tape, you had to first enter a
[Bootstrap Loader](/apps/pdp11/boot/bootstrap/). PDPjs has simplified that process by including the Bootstrap Loader as [Bootstrap Loader](/apps/pdp11/boot/bootstrap/). PDPjs has simplified that process by including the Bootstrap Loader as
just another paper tape image that you can "Load" directly into memory. Once that has been loaded, you can then read any just another paper tape image that you can "Read" directly into memory. Once that has been done, you can then load any
other paper tape image, once you "Attach" it to the paper tape reader. other paper tape image using the Bootstrap Loader, once you "Load" it into the paper tape reader.
{% include machine.html id="test1120" %} {% include machine.html id="test1120" %}

View file

@ -80,7 +80,7 @@ but unlike tapes like [PDP-11 BASIC](/apps/pdp11/tapes/basic/), they don't inclu
documentation for each test to learn the starting procedure, including any switches that should be set first. documentation for each test to learn the starting procedure, including any switches that should be set first.
However, PDPjs makes life a bit simpler for you. As noted for other [DEC PDP-11 Tape Images](/apps/pdp11/tapes/), any However, PDPjs makes life a bit simpler for you. As noted for other [DEC PDP-11 Tape Images](/apps/pdp11/tapes/), any
"Absolute Format" tape can be loaded directly into RAM using the machine's "Load" button instead of "Attach", allowing you "Absolute Format" tape can be read directly into RAM using the machine's "Read" button instead of "Load", allowing you
to bypass the usual three-step process of loading the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) in order to load the to bypass the usual three-step process of loading the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) in order to load the
[Absolute Loader](/apps/pdp11/tapes/absloader/) in order to load the desired tape. [Absolute Loader](/apps/pdp11/tapes/absloader/) in order to load the desired tape.

View file

@ -11,13 +11,13 @@ To load any of the DEC PDP-11 paper tapes listed below, you will need to use a [
with a [PC11 High-Speed Paper Tape Reader/Punch](/devices/pdp11/pc11/), such as this with a [PC11 High-Speed Paper Tape Reader/Punch](/devices/pdp11/pc11/), such as this
[PDP-11/20](/devices/pdp11/machine/1120/basic/debugger), and then follow this three-step process: [PDP-11/20](/devices/pdp11/machine/1120/basic/debugger), and then follow this three-step process:
- Load the [DEC PDP-11 Bootstrap Loader](/apps/pdp11/boot/bootstrap/) - "Read" the [DEC PDP-11 Bootstrap Loader](/apps/pdp11/boot/bootstrap/)
- Attach the [Absolute Loader](absloader/) tape image, and load it with the Bootstrap Loader - "Load" the [Absolute Loader](absloader/) tape image, and read it with the Bootstrap Loader
- Attach one of the "Absolute Format" tape images below, and load it with the Absolute Loader - "Load" one of the "Absolute Format" tape images below, and read it with the Absolute Loader
This mirrors the three-step "real world" process of loading paper tape software. Moreover, any "Absolute This mirrors the three-step "real world" process of loading paper tape software. Moreover, any "Absolute
Format" tape (which should include all the tapes listed below) can be loaded directly into RAM using the Format" tape (which should include all the tapes listed below) can be loaded directly into RAM using the
machine's "Load" button instead of "Attach". In most cases, that eliminates the first two steps. machine's "Read" button instead of "Load". In most cases, that eliminates the first two steps.
Paper Tape Diagnostics Paper Tape Diagnostics
---------------------- ----------------------

View file

@ -12,8 +12,8 @@ website, we have been able to archive the PDP-11 diagnostics shown below. The t
[Default PC11 Configuration](/devices/pdp11/pc11/), so that you can easily load them into any machine with a [Default PC11 Configuration](/devices/pdp11/pc11/), so that you can easily load them into any machine with a
[PC11](/modules/pdp11/lib/pc11.js), such as this [PDP-11/20 with Front Panel and Debugger](/devices/pdp11/machine/1120/panel/debugger/). [PC11](/modules/pdp11/lib/pc11.js), such as this [PDP-11/20 with Front Panel and Debugger](/devices/pdp11/machine/1120/panel/debugger/).
As noted for other [DEC PDP-11 Tape Images](/apps/pdp11/tapes/), these "Absolute Format" tapes can be loaded directly As noted for other [DEC PDP-11 Tape Images](/apps/pdp11/tapes/), these "Absolute Format" tapes can be read directly
into RAM using the machine's "Load" button instead of "Attach", allowing you to bypass the usual three-step process of into RAM using the machine's "Read" button instead of "Load", allowing you to bypass the usual three-step process of
loading the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) in order to load the [Absolute Loader](/apps/pdp11/tapes/absloader/) loading the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) in order to load the [Absolute Loader](/apps/pdp11/tapes/absloader/)
in order to load the desired tape. in order to load the desired tape.
@ -255,7 +255,7 @@ From [bitsavers.org](http://bitsavers.trailing-edge.com/bits/DEC/pdp11/papertape
MD-11 11/70 CPU EXERCISER MD-11 11/70 CPU EXERCISER
------------------------- -------------------------
When started in a [PDP-11/70](/devices/pdp11/machine/1170/panel/debugger/cpuexer/) with no disk drives attached, When started in a [PDP-11/70](/devices/pdp11/machine/1170/panel/debugger/cpuexer/) with no disk drives installed,
this diagnostic displays the following startup information ("EXERCISOR" is DEC's typo, not mine): this diagnostic displays the following startup information ("EXERCISOR" is DEC's typo, not mine):
MAINDEC-11-DEQKC-B...PDP 11/70 CPU EXERCISOR MAINDEC-11-DEQKC-B...PDP 11/70 CPU EXERCISOR

View file

@ -19,10 +19,10 @@
<manifest ref="/apps/pcx86/1981/visicalc/manifest.xml" disk="*"/> <manifest ref="/apps/pcx86/1981/visicalc/manifest.xml" disk="*"/>
<manifest ref="/apps/pcx86/1982/esuite/manifest.xml" disk="*"/> <manifest ref="/apps/pcx86/1982/esuite/manifest.xml" disk="*"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>
<keyboard ref="/devices/pcx86/keyboard/us83-buttons-minimal.xml"/> <keyboard ref="/devices/pcx86/keyboard/us83-buttons-minimal.xml"/>
<debugger id="debugger"/> <debugger id="debugger"/>

View file

@ -18,10 +18,10 @@
<manifest ref="/apps/pcx86/1981/visicalc/manifest.xml" disk="*"/> <manifest ref="/apps/pcx86/1981/visicalc/manifest.xml" disk="*"/>
<manifest ref="/apps/pcx86/1982/esuite/manifest.xml" disk="*"/> <manifest ref="/apps/pcx86/1982/esuite/manifest.xml" disk="*"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>
<cpu id="cpu80188" model="80188" autostart="true" pos="left" padLeft="8px" padBottom="8px"> <cpu id="cpu80188" model="80188" autostart="true" pos="left" padLeft="8px" padBottom="8px">
<control type="button" binding="run">Run</control> <control type="button" binding="run">Run</control>

View file

@ -13,7 +13,9 @@ PDP-11/20 BASIC Demo
The machine below pre-loads the [DEC PDP-11 BASIC](/apps/pdp11/tapes/basic/) tape image into 16Kb of RAM: The machine below pre-loads the [DEC PDP-11 BASIC](/apps/pdp11/tapes/basic/) tape image into 16Kb of RAM:
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/> ```xml
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/>
```
You can also manually load it into memory using the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/). You can also manually load it into memory using the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/).
See the [Bootstrap Loader Demo](/devices/pdp11/machine/1120/bootstrap/) for details. See the [Bootstrap Loader Demo](/devices/pdp11/machine/1120/bootstrap/) for details.

View file

@ -14,7 +14,9 @@ PDP-11/20 BASIC Demo (with Debugger)
The machine below pre-loads the [DEC PDP-11 BASIC](/apps/pdp11/tapes/basic/) tape image into 16Kb of RAM: The machine below pre-loads the [DEC PDP-11 BASIC](/apps/pdp11/tapes/basic/) tape image into 16Kb of RAM:
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/> ```xml
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/>
```
You can also manually load it into memory using the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/). You can also manually load it into memory using the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/).
See the [Bootstrap Loader Demo (with Debugger)](/devices/pdp11/machine/1120/bootstrap/debugger/) for details. See the [Bootstrap Loader Demo (with Debugger)](/devices/pdp11/machine/1120/bootstrap/debugger/) for details.

View file

@ -5,6 +5,9 @@ permalink: /devices/pdp11/machine/1120/bootstrap/
machines: machines:
- id: test1120 - id: test1120
type: pdp11 type: pdp11
autoMount:
PTR:
path: /apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json
--- ---
PDP-11/20 Bootstrap Loader Demo PDP-11/20 Bootstrap Loader Demo
@ -12,24 +15,28 @@ PDP-11/20 Bootstrap Loader Demo
The machine below pre-loads the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) code into 16Kb of RAM: The machine below pre-loads the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) code into 16Kb of RAM:
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/> ```xml
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/>
```
and then pre-attaches the [Absolute Loader](/apps/pdp11/tapes/absloader/) tape image to the PC11 Paper Tape Reader: and then pre-loads the [Absolute Loader](/apps/pdp11/tapes/absloader/) tape image to the PC11 Paper Tape Reader:
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{path:"/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"}' ...>...</device> ```xml
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{PTR:{path:"/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"}}'>...</device>
```
Click "Run" to load the [Absolute Loader](/apps/pdp11/tapes/absloader/). Click "Run" to load the [Absolute Loader](/apps/pdp11/tapes/absloader/).
When the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) is finished, it will HALT, When the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) is finished, it will HALT,
leaving the [Absolute Loader](/apps/pdp11/tapes/absloader/) ready to run immediately after the HALT. leaving the [Absolute Loader](/apps/pdp11/tapes/absloader/) ready to run immediately after the HALT.
You can then select another tape image in the Absolute Loader format, such as [BASIC (Single User)](/apps/pdp11/tapes/basic/), You can then select another tape image in the Absolute Loader format, such as [BASIC (Single User)](/apps/pdp11/tapes/basic/),
click "Attach" and then "Run". click "Load" and then "Run".
If you need to start over, select "Bootstrap Loader (16Kb)" from the list of tapes and click "Load" instead of If you need to start over, select "Bootstrap Loader (16Kb)" from the list of tapes and click "Read" instead of
"Attach", re-installing the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) directly into RAM. "Load", re-installing the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) directly into RAM.
Alternatively, just press the "Reset" button. The RAM component was recently updated to restore pre-loaded images whenever Alternatively, just press the "Reset" button. The RAM component was recently updated to restore pre-loaded images whenever
the entire machine is reset. You'll still need to manually re-attach the [Absolute Loader](/apps/pdp11/tapes/absloader/) the entire machine is reset. You'll still need to manually reload the [Absolute Loader](/apps/pdp11/tapes/absloader/)
tape image, however. tape image, however.
{% include machine.html id="test1120" %} {% include machine.html id="test1120" %}

View file

@ -6,6 +6,9 @@ machines:
- id: test1120 - id: test1120
type: pdp11 type: pdp11
debugger: true debugger: true
autoMount:
PTR:
path: /apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json
--- ---
PDP-11/20 Bootstrap Loader Demo (with Debugger) PDP-11/20 Bootstrap Loader Demo (with Debugger)
@ -13,24 +16,28 @@ PDP-11/20 Bootstrap Loader Demo (with Debugger)
The machine below pre-loads the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) code into 16Kb of RAM: The machine below pre-loads the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) code into 16Kb of RAM:
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/> ```xml
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/>
```
and then pre-attaches the [Absolute Loader](/apps/pdp11/tapes/absloader/) tape image to the PC11 Paper Tape Reader: and then pre-loads the [Absolute Loader](/apps/pdp11/tapes/absloader/) tape image to the PC11 Paper Tape Reader:
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{path:"/apps/pdp11/tapes/DEC-11-L2PC-PO.json"}' ...>...</device> ```xml
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{PTR:{path:"/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"}}'>...</device>
```
Click "Run" to load the [Absolute Loader](/apps/pdp11/tapes/absloader/). Click "Run" to load the [Absolute Loader](/apps/pdp11/tapes/absloader/).
When the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) is finished, it will HALT, When the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) is finished, it will HALT,
leaving the [Absolute Loader](/apps/pdp11/tapes/absloader/) ready to run immediately after the HALT. leaving the [Absolute Loader](/apps/pdp11/tapes/absloader/) ready to run immediately after the HALT.
You can then select another tape image in the Absolute Loader format, such as [BASIC (Single User)](/apps/pdp11/tapes/basic/), You can then select another tape image in the Absolute Loader format, such as [BASIC (Single User)](/apps/pdp11/tapes/basic/),
click "Attach" and then "Run". click "Load" and then "Run".
If you need to start over, select "Bootstrap Loader (16Kb)" from the list of tapes and click "Load" instead of If you need to start over, select "Bootstrap Loader (16Kb)" from the list of tapes and click "Read" instead of
"Attach", re-installing the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) directly into RAM. "Load", re-installing the [Bootstrap Loader](/apps/pdp11/boot/bootstrap/) directly into RAM.
Alternatively, just press the "Reset" button. The RAM component was recently updated to restore pre-loaded images whenever Alternatively, just press the "Reset" button. The RAM component was recently updated to restore pre-loaded images whenever
the entire machine is reset. You'll still need to manually re-attach the [Absolute Loader](/apps/pdp11/tapes/absloader/) the entire machine is reset. You'll still need to manually reload the [Absolute Loader](/apps/pdp11/tapes/absloader/)
tape image, however. tape image, however.
{% include machine.html id="test1120" %} {% include machine.html id="test1120" %}

View file

@ -12,7 +12,9 @@ PDP-11/20 Boot Monitor
The machine below pre-loads the [PDP-11 Boot Monitor](/apps/pdp11/boot/monitor/) into RAM: The machine below pre-loads the [PDP-11 Boot Monitor](/apps/pdp11/boot/monitor/) into RAM:
<ram id="ram" addr="0x0000" size="0xE000" file="/apps/pdp11/boot/monitor/BOOTMON.json" load="0xC000" exec="0xC000"/> ```xml
<ram id="ram" addr="0x0000" size="0xE000" file="/apps/pdp11/boot/monitor/BOOTMON.json" load="0xC000" exec="0xC000"/>
```
{% include machine.html id="test1120" %} {% include machine.html id="test1120" %}

View file

@ -13,6 +13,8 @@ PDP-11/20 Boot Monitor (with Debugger)
The machine below pre-loads the [PDP-11 Boot Monitor](/apps/pdp11/boot/monitor/) into RAM: The machine below pre-loads the [PDP-11 Boot Monitor](/apps/pdp11/boot/monitor/) into RAM:
<ram id="ram" addr="0x0000" size="0xE000" file="/apps/pdp11/boot/monitor/BOOTMON.json" load="0xC000" exec="0xC000"/> ```xml
<ram id="ram" addr="0x0000" size="0xE000" file="/apps/pdp11/boot/monitor/BOOTMON.json" load="0xC000" exec="0xC000"/>
```
{% include machine.html id="test1120" %} {% include machine.html id="test1120" %}

View file

@ -13,6 +13,8 @@ machines:
path: http://archive.pcjs.org/disks/dec/rk03/RK03-RT11-V40.json path: http://archive.pcjs.org/disks/dec/rk03/RK03-RT11-V40.json
RL0: RL0:
path: http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json path: http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json
PTR:
path: /apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json
--- ---
This machine is ready to boot [XXDP+ Diagnostics](/disks/dec/rl02k/xxdp/) ("BOOT RL0") and run This machine is ready to boot [XXDP+ Diagnostics](/disks/dec/rl02k/xxdp/) ("BOOT RL0") and run

View file

@ -19,24 +19,28 @@ listed in the following PC11 Device XML file:
which is typically referenced by a Machine XML file as: which is typically referenced by a Machine XML file as:
<device ref="/devices/pdp11/pc11/default.xml"/> ```xml
<device ref="/devices/pdp11/pc11/default.xml"/>
```
Device XML files not only configure a device, but also list all the resource the device will use, and define UI elements Device XML files not only configure a device, but also list all the resource the device will use, and define UI elements
used to control the device, such as choosing which tape should be "attached" to the PC11 device. For example: used to control the device, such as choosing which tape should be "loaded" into the PC11 device. For example:
<?xml version="1.0" encoding="UTF-8"?> ```xml
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{path:"/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"}' pos="left" width="35%" padLeft="8px" padBottom="8px"> <?xml version="1.0" encoding="UTF-8"?>
<name>Paper Tape Controls</name> <device id="pc11" type="pc11" baudReceive="9600" autoMount='{PTR:{path:"/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"}}' pos="left" width="35%" padLeft="8px" padBottom="8px">
<control type="container"> <name>Paper Tape Controls</name>
<control type="list" binding="listTapes"> <control type="container">
<tape id="tape00" name="Bootstrap Loader (16Kb)" path="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/> <control type="list" binding="listTapes">
<tape id="tape01" name="Absolute Loader" path="/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"/> <tape id="tape00" name="Bootstrap Loader (16Kb)" path="/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"/>
<tape id="tape02" name="BASIC (Single User)" path="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/> <tape id="tape01" name="Absolute Loader" path="/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"/>
</control> <tape id="tape02" name="BASIC (Single User)" path="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/>
<control type="button" binding="attachTape">Attach</control>
<control type="button" binding="loadTape">Load</control>
<control type="description" binding="descTape" padRight="8px"/>
<control type="file" binding="mountTape"/>
<control type="progress" binding="readProgress" pos="default" width="250px" padTop="8px">Tape Progress</control>
</control> </control>
</device> <control type="button" binding="loadTape">Load</control>
<control type="button" binding="readTape">Read</control>
<control type="description" binding="descTape" padRight="8px"/>
<control type="file" binding="mountTape"/>
<control type="progress" binding="readProgress" pos="default" width="250px" padTop="8px">Tape Progress</control>
</control>
</device>
```

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<device id="pc11" type="pc11" baudReceive="9600" autoMount='{path:"/apps/pdp11/tapes/absloader/DEC-11-L2PC-PO.json"}' pos="left" width="35%" padLeft="8px" padBottom="8px"> <device id="pc11" type="pc11" baudReceive="9600" autoMount='{PTR:{path:"/apps/pdp11/boot/bootstrap/BOOTSTRAP-16KB.json"}}' pos="left" width="35%" padLeft="8px" padBottom="8px">
<name>Paper Tape Controls</name> <name>Paper Tape Controls</name>
<control type="container"> <control type="container">
<control type="list" binding="listTapes"> <control type="list" binding="listTapes">
@ -49,8 +49,8 @@
<tape id="diags.tape15" name="MD-11 TEST 15 - CPU EXERCISER" path="/apps/pdp11/tapes/diags/MAINDEC-11-D0OA-PB.json"/> <tape id="diags.tape15" name="MD-11 TEST 15 - CPU EXERCISER" path="/apps/pdp11/tapes/diags/MAINDEC-11-D0OA-PB.json"/>
<tape id="tray02.tape04" name="MD-11 11/70 CPU EXERCISER" path="/apps/pdp11/tapes/diags/MAINDEC-11-DEQKC-B1-PB.json"/> <tape id="tray02.tape04" name="MD-11 11/70 CPU EXERCISER" path="/apps/pdp11/tapes/diags/MAINDEC-11-DEQKC-B1-PB.json"/>
</control> </control>
<control type="button" binding="attachTape">Attach</control>
<control type="button" binding="loadTape">Load</control> <control type="button" binding="loadTape">Load</control>
<control type="button" binding="readTape">Read</control>
<control type="description" binding="descTape" padRight="8px"/> <control type="description" binding="descTape" padRight="8px"/>
<control type="file" binding="mountTape"/> <control type="file" binding="mountTape"/>
<control type="progress" binding="readProgress" pos="default" padTop="8px">Tape Progress</control> <control type="progress" binding="readProgress" pos="default" padTop="8px">Tape Progress</control>

View file

@ -38,7 +38,8 @@ used to control the device, such as choosing which disks should be "auto-mounted
<control type="list" binding="listDisks"> <control type="list" binding="listDisks">
<disk id="disk01" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"/> <disk id="disk01" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="bootDisk">Boot</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDisk"/> <control type="file" binding="mountDisk"/>
</control> </control>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<device id="rk11" type="rk11" autoMountExample='{RK0:{path:"http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"}}' pos="left" width="35%" padLeft="8px" padBottom="8px"> <device id="rk11" type="rk11" autoMount='{RK0:{path:"http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"}}' pos="left" width="35%" padLeft="8px" padBottom="8px">
<name>Disk Drive Controls</name> <name>Disk Drive Controls</name>
<control type="container"> <control type="container">
<control type="list" binding="listDrives"/> <control type="list" binding="listDrives"/>
@ -11,7 +11,8 @@
</disk> </disk>
<disk id="disk04" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"/> <disk id="disk04" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rk03/RK03-XXDP.json"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="bootDisk">Boot</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDisk"/> <control type="file" binding="mountDisk"/>
</control> </control>

View file

@ -39,7 +39,8 @@ used to control the device, such as choosing which disks should be "auto-mounted
<control type="list" binding="listDisks"> <control type="list" binding="listDisks">
<disk id="disk01" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json"/> <disk id="disk01" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="bootDisk">Boot</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDisk"/> <control type="file" binding="mountDisk"/>
</control> </control>

View file

@ -6,7 +6,8 @@
<disk id="disk01" name="RSTS/E v7.0" path="http://archive.pcjs.org/disks/dec/rl01k/RL01K-RSTS-V70.json"/> <disk id="disk01" name="RSTS/E v7.0" path="http://archive.pcjs.org/disks/dec/rl01k/RL01K-RSTS-V70.json"/>
<disk id="disk02" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json"/> <disk id="disk02" name="XXDP+ Diagnostics" path="http://archive.pcjs.org/disks/dec/rl02k/RL02K-XXDP.json"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="bootDisk">Boot</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDisk"/> <control type="file" binding="mountDisk"/>
</control> </control>

View file

@ -517,8 +517,8 @@
<disk path="/pubs/pc/programming/Undocumented_Windows/UNDOC-WIN.json">Book: Undocumented Windows</disk> <disk path="/pubs/pc/programming/Undocumented_Windows/UNDOC-WIN.json">Book: Undocumented Windows</disk>
<disk path="/tests/pcx86/vga/VGABIN.json">VGA Tests (Black Book)</disk> <disk path="/tests/pcx86/vga/VGABIN.json">VGA Tests (Black Book)</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>

View file

@ -9,8 +9,8 @@
<disk path="/disks/pcx86/games/microsoft/adventure/ADVENTURE-1981.json">Microsoft Adventure</disk> <disk path="/disks/pcx86/games/microsoft/adventure/ADVENTURE-1981.json">Microsoft Adventure</disk>
<disk path="/apps/pcx86/1981/visicalc/disk.json">VisiCalc (1981)</disk> <disk path="/apps/pcx86/1981/visicalc/disk.json">VisiCalc (1981)</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>

View file

@ -12,7 +12,7 @@
<control type="list" binding="listDisks"> <control type="list" binding="listDisks">
<manifest ref="/disks/pcx86/cpm/1.1b/manifest.xml" disk="*"/> <manifest ref="/disks/pcx86/cpm/1.1b/manifest.xml" disk="*"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="description" binding="descDisk" padLeft="8px"/> <control type="description" binding="descDisk" padLeft="8px"/>
</fdc> </fdc>
<cpu id="cpu8088" model="8088" autostart="true" pos="left" padLeft="8px" padBottom="8px"> <cpu id="cpu8088" model="8088" autostart="true" pos="left" padLeft="8px" padBottom="8px">

View file

@ -8,6 +8,6 @@
<manifest ref="/disks/pcx86/games/infocom/zork2/manifest.xml" disk="*"/> <manifest ref="/disks/pcx86/games/infocom/zork2/manifest.xml" disk="*"/>
<manifest ref="/disks/pcx86/games/infocom/zork3/manifest.xml" disk="*"/> <manifest ref="/disks/pcx86/games/infocom/zork3/manifest.xml" disk="*"/>
</control> </control>
<control type="button" binding="loadDrive" padRight="8px">Load</control> <control type="button" binding="loadDisk" padRight="8px">Load</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
</fdc> </fdc>

View file

@ -107,8 +107,8 @@
<manifest ref="/pubs/pc/programming/manifest.xml"/> <manifest ref="/pubs/pc/programming/manifest.xml"/>
<disk path="/tests/pcx86/vga/VGABIN.json">VGA Tests (Black Book)</disk> <disk path="/tests/pcx86/vga/VGABIN.json">VGA Tests (Black Book)</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>

View file

@ -8,8 +8,8 @@
<manifest ref="/disks/pcx86/games/microsoft/adventure/manifest.xml"/> <manifest ref="/disks/pcx86/games/microsoft/adventure/manifest.xml"/>
<manifest ref="/apps/pcx86/1981/visicalc/manifest.xml"/> <manifest ref="/apps/pcx86/1981/visicalc/manifest.xml"/>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="button" binding="saveDrive" padRight="8px">Save</control> <control type="button" binding="saveDisk" padRight="8px">Save</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>

View file

@ -15,6 +15,6 @@
<disk path="/disks/pcx86/windows/1.03/05-APPS/">Windows 1.03 (APPS)</disk> <disk path="/disks/pcx86/windows/1.03/05-APPS/">Windows 1.03 (APPS)</disk>
<disk path="/disks/pcx86/windows/1.03/06-WRITE/">Windows 1.03 (WRITE)</disk> <disk path="/disks/pcx86/windows/1.03/06-WRITE/">Windows 1.03 (WRITE)</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="description" binding="descDisk" padLeft="8px"/> <control type="description" binding="descDisk" padLeft="8px"/>
</fdc> </fdc>

View file

@ -100,7 +100,7 @@ disks at will, we'll include some UI controls.
<disk path="">None</disk> <disk path="">None</disk>
<disk path="pcdos-1.00.json">PC-DOS 1.0</disk> <disk path="pcdos-1.00.json">PC-DOS 1.0</disk>
</control> </control>
<control type="button" class="input" binding="loadDrive">Load</control> <control type="button" class="input" binding="loadDisk">Load</control>
</control> </control>
</fdc> </fdc>
... ...

View file

@ -19,7 +19,7 @@
<control type="list" binding="listDisks"> <control type="list" binding="listDisks">
<disk path="PCDOS100.json">PC-DOS 1.00</disk> <disk path="PCDOS100.json">PC-DOS 1.00</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
</control> </control>
</fdc> </fdc>
<chipset id="chipset" model="5150" sw1="01000001" sw2="11110000"/> <chipset id="chipset" model="5150" sw1="01000001" sw2="11110000"/>

View file

@ -59,7 +59,7 @@
<disk path="PCDOS100.json">PC-DOS 1.00</disk> <disk path="PCDOS100.json">PC-DOS 1.00</disk>
<disk path="visicalc.json" href="http://www.bricklin.com/history/vclicense.htm" desc="VisiCalc License">VisiCalc</disk> <disk path="visicalc.json" href="http://www.bricklin.com/history/vclicense.htm" desc="VisiCalc License">VisiCalc</disk>
</control> </control>
<control type="button" binding="loadDrive">Load</control> <control type="button" binding="loadDisk">Load</control>
<control type="description" binding="descDisk" padLeft="8px"/> <control type="description" binding="descDisk" padLeft="8px"/>
</control> </control>
</fdc> </fdc>

View file

@ -650,8 +650,8 @@ l.toJSON=function(){var a;a=0;for(var b;b=ep(this,a++);)xp(b);a=JSON.stringify(t
function xp(a){var b=a.data,c=b.length;if(c<<2==a.length){for(var d=c-1,e=b[d],f=0;d--&&b[d]===e;)f++;f++&&(b.length=c-f,a.pattern=e)}}function yp(a){bb.call(this,"FDC",a,yp,524288);this.dmaRead=this.el;this.dmaWrite=this.fl;this.dmaFormat=this.xl;this.U=a.autoMount||null;this.fa=a.sortBy||"name";"none"==this.fa&&(this.fa=null);this.B=[];this.ia=!La("Mobi")&&window&&"FileReader"in window}jb(yp);aa={}; function xp(a){var b=a.data,c=b.length;if(c<<2==a.length){for(var d=c-1,e=b[d],f=0;d--&&b[d]===e;)f++;f++&&(b.length=c-f,a.pattern=e)}}function yp(a){bb.call(this,"FDC",a,yp,524288);this.dmaRead=this.el;this.dmaWrite=this.fl;this.dmaFormat=this.xl;this.U=a.autoMount||null;this.fa=a.sortBy||"name";"none"==this.fa&&(this.fa=null);this.B=[];this.ia=!La("Mobi")&&window&&"FileReader"in window}jb(yp);aa={};
var zp={3:{Ud:3,ge:0,name:aa.gp},4:{Ud:2,ge:1,name:aa.ep},5:{Ud:9,ge:7,name:aa.kp},6:{Ud:9,ge:7,name:aa.$o},7:{Ud:2,ge:0,name:aa.bp},8:{Ud:1,ge:2,name:aa.fp},10:{Ud:2,ge:7,name:aa.ap},13:{Ud:6,ge:7,name:aa.Xo},15:{Ud:3,ge:0,name:aa.cp}};l=yp.prototype; var zp={3:{Ud:3,ge:0,name:aa.gp},4:{Ud:2,ge:1,name:aa.ep},5:{Ud:9,ge:7,name:aa.kp},6:{Ud:9,ge:7,name:aa.$o},7:{Ud:2,ge:0,name:aa.bp},8:{Ud:1,ge:2,name:aa.fp},10:{Ud:2,ge:7,name:aa.ap},13:{Ud:6,ge:7,name:aa.Xo},15:{Ud:3,ge:0,name:aa.cp}};l=yp.prototype;
l.Pb=function(a,b,c){var d=this;switch(b){case "listDisks":this.qa[b]=c;if(this.fa){b=[];for(a=0;a<c.options.length;a++)b.push(c.options[a]);b.sort(function(a,b){return"path"!=d.fa?a.text.localeCompare(b.text):a.value.localeCompare(b.value)});for(a=0;a<b.length;a++)try{c.options[a]=b[a]}catch(e){break}}c.onchange=function(){var a=d.qa.descDisk,b=c.options[c.selectedIndex];if(a&&b){var g={};if(b=b.getAttribute("data-value"))try{g=eval("("+b+")")}catch(h){w("FDC option error: "+h.message)}b=g.desc; l.Pb=function(a,b,c){var d=this;switch(b){case "listDisks":this.qa[b]=c;if(this.fa){b=[];for(a=0;a<c.options.length;a++)b.push(c.options[a]);b.sort(function(a,b){return"path"!=d.fa?a.text.localeCompare(b.text):a.value.localeCompare(b.value)});for(a=0;a<b.length;a++)try{c.options[a]=b[a]}catch(e){break}}c.onchange=function(){var a=d.qa.descDisk,b=c.options[c.selectedIndex];if(a&&b){var g={};if(b=b.getAttribute("data-value"))try{g=eval("("+b+")")}catch(h){w("FDC option error: "+h.message)}b=g.desc;
void 0===b&&(b="");g=g.href;void 0!==g&&(b='<a href="'+g+'" target="_blank">'+b+"</a>");a.innerHTML=b}};return!0;case "descDisk":case "listDrives":return this.qa[b]=c,c.onchange=function(){var a=ea(c.value,10);null!=a&&Ap(d,a)},!0;case "loadDrive":return this.qa[b]=c,c.onclick=function(){var a=d.qa.listDisks;a&&Bp(d,a.options[a.selectedIndex].text,a.value)},!0;case "saveDrive":if(!this.ia){c.parentNode.removeChild(c);break}this.qa[b]=c;c.onclick=function(){var a=d.qa.listDrives;a&&a.options&&d.A&& void 0===b&&(b="");g=g.href;void 0!==g&&(b='<a href="'+g+'" target="_blank">'+b+"</a>");a.innerHTML=b}};return!0;case "descDisk":case "listDrives":return this.qa[b]=c,c.onchange=function(){var a=ea(c.value,10);null!=a&&Ap(d,a)},!0;case "loadDisk":return this.qa[b]=c,c.onclick=function(){var a=d.qa.listDisks;a&&Bp(d,a.options[a.selectedIndex].text,a.value)},!0;case "saveDisk":if(!this.ia){c.parentNode.removeChild(c);break}this.qa[b]=c;c.onclick=function(){var a=d.qa.listDrives;a&&a.options&&d.A&&((a=
((a=d.A[ea(a.value,10)||0])?(a=a.za)?(a=Na(wp(a),"octet-stream",!0,a.Ug.replace(".json",".img")),w(a)):d.Na("No diskette loaded in drive."):d.Na("No diskette drive selected."))};return!0;case "mountDrive":if(this.ia)return this.qa[b]=c,c.addEventListener("change",function(){var a=c.children[0];a.children[1].disabled=!a.children[0].files.length}),c.onsubmit=function(a){if(a=a.currentTarget[1].files[0]){var b=a.name;Bp(d,ja(b,!0),b,a)}return!1},!0;c.parentNode.removeChild(c)}return!1}; d.A[ea(a.value,10)||0])?(a=a.za)?(a=Na(wp(a),"octet-stream",!0,a.Ug.replace(".json",".img")),w(a)):d.Na("No diskette loaded in drive."):d.Na("No diskette drive selected."))};return!0;case "mountDisk":if(this.ia)return this.qa[b]=c,c.addEventListener("change",function(){var a=c.children[0];a.children[1].disabled=!a.children[0].files.length}),c.onsubmit=function(a){if(a=a.currentTarget[1].files[0]){var b=a.name;Bp(d,ja(b,!0),b,a)}return!1},!0;c.parentNode.removeChild(c)}return!1};
l.Jc=function(a,b,c,d){this.ga=b;this.F=c;this.ha=d;this.X=a;this.N=Jb(a,"ChipSet");if((this.U=Yc(this.X,"autoMount")||this.U)&&"string"==typeof this.U)try{this.U=eval("("+this.U+")")}catch(e){w("FDC auto-mount error: "+e.message+" ("+this.U+")"),this.U=null}Cp(this);qc(b,this,Dp);yc(b,this,Ep);Fp(this,"None","",!0);this.ia&&Fp(this,"Local Disk","?");Fp(this,"Remote Disk","??");Gp(this)||xb(this)}; l.Jc=function(a,b,c,d){this.ga=b;this.F=c;this.ha=d;this.X=a;this.N=Jb(a,"ChipSet");if((this.U=Yc(this.X,"autoMount")||this.U)&&"string"==typeof this.U)try{this.U=eval("("+this.U+")")}catch(e){w("FDC auto-mount error: "+e.message+" ("+this.U+")"),this.U=null}Cp(this);qc(b,this,Dp);yc(b,this,Ep);Fp(this,"None","",!0);this.ia&&Fp(this,"Local Disk","?");Fp(this,"Remote Disk","??");Gp(this)||xb(this)};
l.hc=function(a,b){if(!b){if(!a||!this.restore){if(this.reset(),this.X.lh){this.B=[];for(a=0;a<this.A.length;a++)Hp(this,a,!0);Gp(this,!0)}}else if(!this.restore(a))return!1;if(a=this.qa.listDrives){for(;a.firstChild;)a.removeChild(a.firstChild);a.value="";for(b=0;b<this.ka;b++){var c=document.createElement("option");c.value=b;c.text=String.fromCharCode(65+b)+":";a.appendChild(c)}0<this.ka&&(a.value="0",Ap(this,0))}}return!0};l.gc=function(a){return a?this.save():!0};l.reset=function(){Cp(this)}; l.hc=function(a,b){if(!b){if(!a||!this.restore){if(this.reset(),this.X.lh){this.B=[];for(a=0;a<this.A.length;a++)Hp(this,a,!0);Gp(this,!0)}}else if(!this.restore(a))return!1;if(a=this.qa.listDrives){for(;a.firstChild;)a.removeChild(a.firstChild);a.value="";for(b=0;b<this.ka;b++){var c=document.createElement("option");c.value=b;c.text=String.fromCharCode(65+b)+":";a.appendChild(c)}0<this.ka&&(a.value="0",Ap(this,0))}}return!0};l.gc=function(a){return a?this.save():!0};l.reset=function(){Cp(this)};
l.save=function(){var a=new qf(this);a.set(0,Ip(this));return a.data()};l.restore=function(a){return Cp(this,a[0])}; l.save=function(){var a=new qf(this);a.set(0,Ip(this));return a.data()};l.restore=function(a){return Cp(this,a[0])};

View file

@ -599,8 +599,8 @@ l.toJSON=function(){var a;a=0;for(var b;b=nm(this,a++);)vm(b);a=JSON.stringify(t
function vm(a){var b=a.data,c=b.length;if(c<<2==a.length){for(var d=c-1,e=b[d],f=0;d--&&b[d]===e;)f++;f++&&(b.length=c-f,a.pattern=e)}}function wm(a){Ka.call(this,"FDC",a,wm);this.dmaRead=this.Tj;this.dmaWrite=this.Uj;this.dmaFormat=this.jk;this.K=a.autoMount||null;this.W=a.sortBy||"name";"none"==this.W&&(this.W=null);this.C=[];this.Y=!za("Mobi")&&window&&"FileReader"in window}Ta(wm);ba={}; function vm(a){var b=a.data,c=b.length;if(c<<2==a.length){for(var d=c-1,e=b[d],f=0;d--&&b[d]===e;)f++;f++&&(b.length=c-f,a.pattern=e)}}function wm(a){Ka.call(this,"FDC",a,wm);this.dmaRead=this.Tj;this.dmaWrite=this.Uj;this.dmaFormat=this.jk;this.K=a.autoMount||null;this.W=a.sortBy||"name";"none"==this.W&&(this.W=null);this.C=[];this.Y=!za("Mobi")&&window&&"FileReader"in window}Ta(wm);ba={};
var xm={3:{hd:3,xd:0,name:ba.Fn},4:{hd:2,xd:1,name:ba.Dn},5:{hd:9,xd:7,name:ba.Jn},6:{hd:9,xd:7,name:ba.zn},7:{hd:2,xd:0,name:ba.Bn},8:{hd:1,xd:2,name:ba.En},10:{hd:2,xd:7,name:ba.An},13:{hd:6,xd:7,name:ba.wn},15:{hd:3,xd:0,name:ba.Cn}};l=wm.prototype; var xm={3:{hd:3,xd:0,name:ba.Fn},4:{hd:2,xd:1,name:ba.Dn},5:{hd:9,xd:7,name:ba.Jn},6:{hd:9,xd:7,name:ba.zn},7:{hd:2,xd:0,name:ba.Bn},8:{hd:1,xd:2,name:ba.En},10:{hd:2,xd:7,name:ba.An},13:{hd:6,xd:7,name:ba.wn},15:{hd:3,xd:0,name:ba.Cn}};l=wm.prototype;
l.zb=function(a,b,c){var d=this;switch(b){case "listDisks":this.la[b]=c;if(this.W){b=[];for(a=0;a<c.options.length;a++)b.push(c.options[a]);b.sort(function(a,b){return"path"!=d.W?a.text.localeCompare(b.text):a.value.localeCompare(b.value)});for(a=0;a<b.length;a++)try{c.options[a]=b[a]}catch(e){break}}c.onchange=function(){var a=d.la.descDisk,b=c.options[c.selectedIndex];if(a&&b){var g={};if(b=b.getAttribute("data-value"))try{g=eval("("+b+")")}catch(h){r("FDC option error: "+h.message)}b=g.desc;void 0=== l.zb=function(a,b,c){var d=this;switch(b){case "listDisks":this.la[b]=c;if(this.W){b=[];for(a=0;a<c.options.length;a++)b.push(c.options[a]);b.sort(function(a,b){return"path"!=d.W?a.text.localeCompare(b.text):a.value.localeCompare(b.value)});for(a=0;a<b.length;a++)try{c.options[a]=b[a]}catch(e){break}}c.onchange=function(){var a=d.la.descDisk,b=c.options[c.selectedIndex];if(a&&b){var g={};if(b=b.getAttribute("data-value"))try{g=eval("("+b+")")}catch(h){r("FDC option error: "+h.message)}b=g.desc;void 0===
b&&(b="");g=g.href;void 0!==g&&(b='<a href="'+g+'" target="_blank">'+b+"</a>");a.innerHTML=b}};return!0;case "descDisk":case "listDrives":return this.la[b]=c,c.onchange=function(){var a=ea(c.value,10);null!=a&&ym(d,a)},!0;case "loadDrive":return this.la[b]=c,c.onclick=function(){var a=d.la.listDisks;a&&zm(d,a.options[a.selectedIndex].text,a.value)},!0;case "saveDrive":if(!this.Y){c.parentNode.removeChild(c);break}this.la[b]=c;c.onclick=function(){var a=d.la.listDrives;a&&a.options&&d.B&&((a=d.B[ea(a.value, b&&(b="");g=g.href;void 0!==g&&(b='<a href="'+g+'" target="_blank">'+b+"</a>");a.innerHTML=b}};return!0;case "descDisk":case "listDrives":return this.la[b]=c,c.onchange=function(){var a=ea(c.value,10);null!=a&&ym(d,a)},!0;case "loadDisk":return this.la[b]=c,c.onclick=function(){var a=d.la.listDisks;a&&zm(d,a.options[a.selectedIndex].text,a.value)},!0;case "saveDisk":if(!this.Y){c.parentNode.removeChild(c);break}this.la[b]=c;c.onclick=function(){var a=d.la.listDrives;a&&a.options&&d.B&&((a=d.B[ea(a.value,
10)||0])?(a=a.ua)?(a=Aa(um(a),"octet-stream",!0,a.th.replace(".json",".img")),r(a)):d.Ba("No diskette loaded in drive."):d.Ba("No diskette drive selected."))};return!0;case "mountDrive":if(this.Y)return this.la[b]=c,c.addEventListener("change",function(){var a=c.children[0];a.children[1].disabled=!a.children[0].files.length}),c.onsubmit=function(a){if(a=a.currentTarget[1].files[0]){var b=a.name;zm(d,ga(b,!0),b,a)}return!1},!0;c.parentNode.removeChild(c)}return!1}; 10)||0])?(a=a.ua)?(a=Aa(um(a),"octet-stream",!0,a.th.replace(".json",".img")),r(a)):d.Ba("No diskette loaded in drive."):d.Ba("No diskette drive selected."))};return!0;case "mountDisk":if(this.Y)return this.la[b]=c,c.addEventListener("change",function(){var a=c.children[0];a.children[1].disabled=!a.children[0].files.length}),c.onsubmit=function(a){if(a=a.currentTarget[1].files[0]){var b=a.name;zm(d,ga(b,!0),b,a)}return!1},!0;c.parentNode.removeChild(c)}return!1};
l.pc=function(a,b,c,d){this.ia=b;this.A=c;this.Ia=d;this.ba=a;this.S=mb(a,"ChipSet");if((this.K=nc(this.ba,"autoMount")||this.K)&&"string"==typeof this.K)try{this.K=eval("("+this.K+")")}catch(e){r("FDC auto-mount error: "+e.message+" ("+this.K+")"),this.K=null}Am(this);Sb(b,this,Bm);Ub(b,this,Cm);Dm(this,"None","",!0);this.Y&&Dm(this,"Local Disk","?");Dm(this,"Remote Disk","??");Em(this)||t(this)}; l.pc=function(a,b,c,d){this.ia=b;this.A=c;this.Ia=d;this.ba=a;this.S=mb(a,"ChipSet");if((this.K=nc(this.ba,"autoMount")||this.K)&&"string"==typeof this.K)try{this.K=eval("("+this.K+")")}catch(e){r("FDC auto-mount error: "+e.message+" ("+this.K+")"),this.K=null}Am(this);Sb(b,this,Bm);Ub(b,this,Cm);Dm(this,"None","",!0);this.Y&&Dm(this,"Local Disk","?");Dm(this,"Remote Disk","??");Em(this)||t(this)};
l.Ub=function(a,b){if(!b){if(!a||!this.restore){if(this.reset(),this.ba.pg){this.C=[];for(a=0;a<this.B.length;a++)Fm(this,a,!0);Em(this,!0)}}else if(!this.restore(a))return!1;if(a=this.la.listDrives){for(;a.firstChild;)a.removeChild(a.firstChild);a.value="";for(b=0;b<this.Z;b++){var c=document.createElement("option");c.value=b;c.text=String.fromCharCode(65+b)+":";a.appendChild(c)}0<this.Z&&(a.value="0",ym(this,0))}}return!0};l.Tb=function(a){return a?this.save():!0};l.reset=function(){Am(this)}; l.Ub=function(a,b){if(!b){if(!a||!this.restore){if(this.reset(),this.ba.pg){this.C=[];for(a=0;a<this.B.length;a++)Fm(this,a,!0);Em(this,!0)}}else if(!this.restore(a))return!1;if(a=this.la.listDrives){for(;a.firstChild;)a.removeChild(a.firstChild);a.value="";for(b=0;b<this.Z;b++){var c=document.createElement("option");c.value=b;c.text=String.fromCharCode(65+b)+":";a.appendChild(c)}0<this.Z&&(a.value="0",ym(this,0))}}return!0};l.Tb=function(a){return a?this.save():!0};l.reset=function(){Am(this)};
l.save=function(){var a=new de(this);a.set(0,Gm(this));return a.data()};l.restore=function(a){return Am(this,a[0])}; l.save=function(){var a=new de(this);a.set(0,Gm(this));return a.data()};l.restore=function(a){return Am(this,a[0])};

View file

@ -49,7 +49,7 @@ Bindings
For use with a control of type *list*. This list must be manually populated, using &lt;disk&gt; tags. For use with a control of type *list*. This list must be manually populated, using &lt;disk&gt; tags.
See the example below. See the example below.
* *loadDrive* * *loadDisk*
For use with a control of type *button*, to load the selected diskette image into the selected drive. For use with a control of type *button*, to load the selected diskette image into the selected drive.
This control is also used to unload diskette images. Select the diskette you want to unload, then select This control is also used to unload diskette images. Select the diskette you want to unload, then select
@ -64,7 +64,7 @@ Example
<control type="list" class="input" binding="listDisks"> <control type="list" class="input" binding="listDisks">
<disk path="pcdos-1.00.json">PC-DOS 1.0</disk> <disk path="pcdos-1.00.json">PC-DOS 1.0</disk>
</control> </control>
<control type="button" class="input" binding="loadDrive">Load Drive</control> <control type="button" class="input" binding="loadDisk">Load</control>
</control> </control>
</fdc> </fdc>
``` ```
@ -74,7 +74,7 @@ Output
```html ```html
<div id="..." class="pc-fdc pc-component"> <div id="..." class="pc-fdc pc-component">
<div class="pc-container"> <div class="pc-container">
<div class="pcx86-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDrive:'...'"> <div class="pcx86-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDisk:'...'">
</div> </div>
</div> </div>
</div> </div>

View file

@ -517,7 +517,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
}; };
return true; return true;
case "loadDrive": case "loadDisk":
this.bindings[sBinding] = control; this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) { control.onclick = function onClickLoadDrive(event) {
@ -530,7 +530,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
}; };
return true; return true;
case "saveDrive": case "saveDisk":
/* /*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference * Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there * to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@ -575,7 +575,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
}; };
return true; return true;
case "mountDrive": case "mountDisk":
if (!this.fLocalDisks) { if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available"); if (DEBUG) this.log("Local disk support not available");
/* /*

View file

@ -568,7 +568,7 @@ HDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
var drive = hdc.aDrives && hdc.aDrives[iDrive]; var drive = hdc.aDrives && hdc.aDrives[iDrive];
if (drive && drive.disk) { if (drive && drive.disk) {
/* /*
* Note the similarity (and hence factoring opportunity) between this code and the FDC's "saveDrive" binding. * Note the similarity (and hence factoring opportunity) between this code and the FDC's "saveDisk" binding.
*/ */
var disk = drive.disk; var disk = drive.disk;
if (DEBUG) hdc.println("saving disk " + disk.sDiskPath + "..."); if (DEBUG) hdc.println("saving disk " + disk.sDiskPath + "...");

View file

@ -203,6 +203,13 @@ CPUPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.flags.autoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : !!sAutoStart)); this.flags.autoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : !!sAutoStart));
} }
/*
* Start running automatically on power-up, assuming there's no Debugger and no "Run" button.
*/
if ((!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) {
this.flags.autoStart = true;
}
this.setReady(); this.setReady();
}; };
@ -328,10 +335,10 @@ CPUPDP11.prototype.powerDown = function(fSave, fShutdown)
*/ */
CPUPDP11.prototype.autoStart = function() CPUPDP11.prototype.autoStart = function()
{ {
/* if (this.flags.running) {
* Start running automatically on power-up, assuming there's no Debugger and no "Run" button return true;
*/ }
if (this.flags.autoStart || (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) { if (this.flags.autoStart) {
/* /*
* We used to also set fUpdateFocus when calling startCPU(), on the assumption that in the "auto-starting" * We used to also set fUpdateFocus when calling startCPU(), on the assumption that in the "auto-starting"
* context, a machine without focus is like a day without sunshine, but in reality, focus should only be * context, a machine without focus is like a day without sunshine, but in reality, focus should only be

View file

@ -481,13 +481,13 @@ CPUStatePDP11.prototype.setMMR3 = function(newMMR3)
}; };
/** /**
* setReset(addr, fReset) * setReset(addr, fStart)
* *
* @this {CPUStatePDP11} * @this {CPUStatePDP11}
* @param {number} addr * @param {number} addr
* @param {boolean} [fReset] (true if called in the context of a complete reset, obviating the need to notify the Debugger) * @param {boolean|undefined} fStart (true if a "startable" image was just loaded, false if not)
*/ */
CPUStatePDP11.prototype.setReset = function(addr, fReset) CPUStatePDP11.prototype.setReset = function(addr, fStart)
{ {
this.addrReset = addr; this.addrReset = addr;
@ -495,17 +495,25 @@ CPUStatePDP11.prototype.setReset = function(addr, fReset)
this.setPC(addr); this.setPC(addr);
this.setPSW(0); this.setPSW(0);
if (!fReset && this.dbg) { if (fStart) {
/* this.autoStart();
* TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that }
* when stopCPU() stops a running CPU, the Debugger gets notified, so again, no need to notify it here. else {
* if (this.dbg) {
* TODO: There are more serious problems to deal with if another component is slamming a new PC down /*
* the CPU's throat (presumably while also dropping some new code into RAM) while the CPU was still running; * TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that
* we should probably force a complete reset if the CPU is running, but for now, it's up to the user * when stopCPU() stops a running CPU, the Debugger gets notified, so again, no need to notify it here.
* to hit the reset button themselves. *
*/ * TODO: There are more serious problems to deal with if another component is slamming a new PC down
if (!this.stopCPU()) this.dbg.updateStatus(); * the CPU's throat (presumably while also dropping some new code into RAM) while the CPU was still running;
* we should probably force a complete reset if the CPU is running, but for now, it's up to the user
* to hit the reset button themselves.
*/
if (!this.stopCPU()) this.dbg.updateStatus();
}
else if (fStart === false) {
this.stopCPU();
}
} }
}; };

View file

@ -44,8 +44,8 @@ if (NODE) {
* The PC11 component has the following component-specific (parms) properties: * The PC11 component has the following component-specific (parms) properties:
* *
* autoMount: a JSON-encoded object containing 'name' and 'path' properties, describing a * autoMount: a JSON-encoded object containing 'name' and 'path' properties, describing a
* tape resource to automatically attach at startup (only the "attach" operation is supported * tape resource to automatically load at startup (only the "load" operation is supported
* for autoMount; if you want to "load" a tape image directly into RAM at startup, you must * for autoMount; if you want to "read" a tape image directly into RAM at startup, you must
* ask the RAM component to do that). * ask the RAM component to do that).
* *
* baudReceive: the default number of bits/second that the device should receive data at; * baudReceive: the default number of bits/second that the device should receive data at;
@ -67,11 +67,13 @@ function PC11(parms)
{ {
Component.call(this, "PC11", parms, PC11); Component.call(this, "PC11", parms, PC11);
this.sDevice = "PTR"; // TODO: Make the device name configurable
/* /*
* We record any 'autoMount' object now, but we no longer parse it until initBus(), because the * We record any 'autoMount' object now, but we no longer parse it until initBus(), because the
* Computer's getMachineParm() service may have an override for us. * Computer's getMachineParm() service may have an override for us.
*/ */
this.configMount = parms['autoMount'] || null; this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0; this.cAutoMount = 0;
this.nBaudReceive = parms['baudReceive'] || PDP11.PC11.PRS.BAUD; this.nBaudReceive = parms['baudReceive'] || PDP11.PC11.PRS.BAUD;
@ -124,6 +126,30 @@ PC11.CSSCLASS = {
PROGRESS_BAR: PDP11.CSSCLASS + "-progress-bar" PROGRESS_BAR: PDP11.CSSCLASS + "-progress-bar"
}; };
/**
* parseConfig(config)
*
* @this {PC11}
* @param {*} config
* @return {*}
*/
PC11.prototype.parseConfig = function(config)
{
if (config && typeof config == "string") {
try {
/*
* The most likely source of any exception will be right here, where we're parsing
* this JSON-encoded data.
*/
config = eval("(" + config + ")");
} catch (e) {
Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
config = null;
}
}
return config || {};
};
/** /**
* setBinding(sType, sBinding, control, sValue) * setBinding(sType, sBinding, control, sValue)
* *
@ -170,18 +196,18 @@ PC11.prototype.setBinding = function(sType, sBinding, control, sValue)
return true; return true;
/* /*
* "loadTape" operation must do pretty much everything that the "attachTape" does, but whereas the attach * "readTape" operation must do pretty much everything that the "loadTape" does, but whereas the load
* operation records the bytes in aTapeData, the load operation stuffs them directly into the machine's memory; * operation records the bytes in aTapeData, the read operation stuffs them directly into the machine's memory;
* the former sets nTapeTarget to TARGET.READER, while the latter sets it to TARGET.MEMORY. * the former sets nTapeTarget to TARGET.READER, while the latter sets it to TARGET.MEMORY.
*/ */
case "loadTape": case "readTape":
nTapeTarget = PC11.TARGET.MEMORY; nTapeTarget = PC11.TARGET.MEMORY;
/* falls through */ /* falls through */
case "attachTape": case "loadTape":
if (!nTapeTarget) nTapeTarget = PC11.TARGET.READER; if (!nTapeTarget) nTapeTarget = PC11.TARGET.READER;
this.bindings[sBinding] = control; this.bindings[sBinding] = control;
control.onclick = function onClickLoadTape(event) { control.onclick = function onClickReadTape(event) {
var controlTapes = pc11.bindings["listTapes"]; var controlTapes = pc11.bindings["listTapes"];
if (controlTapes) { if (controlTapes) {
var sTapeName = controlTapes.options[controlTapes.selectedIndex].text; var sTapeName = controlTapes.options[controlTapes.selectedIndex].text;
@ -263,20 +289,15 @@ PC11.prototype.initBus = function(cmp, bus, cpu, dbg)
var pc11 = this; var pc11 = this;
this.configMount = this.cmp.getMachineParm('autoMount') || this.configMount; var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
if (this.configMount) { /*
if (typeof this.configMount == "string") { * Add only devices from the machine-wide autoMount configuration that match devices managed by this component.
try { */
/* if (configMount) {
* The most likely source of any exception will be right here, where we're parsing for (var sDevice in configMount) {
* this JSON-encoded data. if (sDevice != this.sDevice) continue;
*/ this.configMount[sDevice] = configMount[sDevice];
this.configMount = eval("(" + this.configMount + ")");
} catch (e) {
Component.error("PC11 auto-mount error: " + e.message + " (" + this.configMount + ")");
this.configMount = null;
}
} }
} }
@ -332,7 +353,7 @@ PC11.prototype.powerDown = function(fSave, fShutdown)
/** /**
* reset() * reset()
* *
* TODO: Consider making our reset() handler ALSO restore the original attached tape, in much the same * TODO: Consider making our reset() handler ALSO restore the original loaded tape, in much the same
* way the RAM component now restores the original predefined memory or tape image after resetting the RAM. * way the RAM component now restores the original predefined memory or tape image after resetting the RAM.
* *
* @this {PC11} * @this {PC11}
@ -353,9 +374,10 @@ PC11.prototype.reset = function()
PC11.prototype.autoMount = function(fRemount) PC11.prototype.autoMount = function(fRemount)
{ {
if (!fRemount) this.cAutoMount = 0; if (!fRemount) this.cAutoMount = 0;
if (this.configMount) { var configMount = this.configMount[this.sDevice];
var sTapePath = this.configMount['path'] || ""; if (configMount) {
var sTapeName = this.configMount['name'] || this.findTape(sTapePath); var sTapePath = configMount['path'] || "";
var sTapeName = configMount['name'] || this.findTape(sTapePath);
if (sTapePath && sTapeName) { if (sTapePath && sTapeName) {
/* /*
* TODO: Provide a way to autoMount tapes into MEMORY as well as READER. * TODO: Provide a way to autoMount tapes into MEMORY as well as READER.
@ -460,7 +482,7 @@ PC11.prototype.loadTape = function(sTapeName, sTapePath, nTapeTarget, fAutoMount
* Now that we're calling parseTape() again (so that the current tape can either be restarted on * Now that we're calling parseTape() again (so that the current tape can either be restarted on
* the reader or reloaded into RAM), we can also rely on it to display an appropriate status message, too. * the reader or reloaded into RAM), we can also rely on it to display an appropriate status message, too.
* *
* this.status(this.nTapeTarget == PC11.TARGET.READER? "tape attached" : "tape loaded"); * this.status(this.nTapeTarget == PC11.TARGET.READER? "tape loaded" : "tape read");
*/ */
this.parseTape(this.sTapeName, this.sTapePath, this.nTapeTarget, this.aBytes, this.addrLoad, this.addrExec); this.parseTape(this.sTapeName, this.sTapePath, this.nTapeTarget, this.aBytes, this.addrLoad, this.addrExec);
} }
@ -705,23 +727,28 @@ PC11.prototype.parseTape = function(sTapeName, sTapePath, nTapeTarget, aBytes, a
* *
* For example, the "Absolute Loader" tape is NOT itself in the Absolute Loader format. You just have * For example, the "Absolute Loader" tape is NOT itself in the Absolute Loader format. You just have
* to know that in order to load that tape, you must first load the appropriate "Bootstrap Loader" (which * to know that in order to load that tape, you must first load the appropriate "Bootstrap Loader" (which
* DOES include its own hard-coded load address), attach the "Absolute Loader" tape, and then run the * DOES include its own hard-coded load address), load the "Absolute Loader" tape, and then run the
* "Bootstrap Loader". * "Bootstrap Loader".
*/ */
if (!this.ram || !this.ram.loadImage(aBytes, addrLoad, addrExec)) { if (!this.ram || !this.ram.loadImage(aBytes, addrLoad, addrExec, null, false)) {
this.sTapeName = ""; /*
this.sTapePath = ""; * This doesn't seem to serve any purpose, other than to be annoying, because perhaps you accidentally
this.sTapeSource = PC11.SOURCE.NONE; * clicked "Read" instead of "Load"....
this.nTapeTarget = PC11.TARGET.NONE; *
this.notice('No load address available for tape "' + sTapeName + '"'); * this.sTapeName = "";
* this.sTapePath = "";
* this.sTapeSource = PC11.SOURCE.NONE;
* this.nTapeTarget = PC11.TARGET.NONE;
*/
this.notice('No valid memory address for tape "' + sTapeName + '"');
return; return;
} }
this.status('Loaded tape "' + sTapeName + '"'); this.status('Read tape "' + sTapeName + '"');
return; return;
} }
this.iTapeData = 0; this.iTapeData = 0;
this.aTapeData = aBytes; this.aTapeData = aBytes;
this.status('Attached tape "' + sTapeName + '"'); this.status('Loaded tape "' + sTapeName + '"');
this.displayProgress(0); this.displayProgress(0);
}; };

View file

@ -260,7 +260,7 @@ RAMPDP11.prototype.reset = function()
}; };
/** /**
* loadImage(aBytes, addrLoad, addrExec, addrInit, fReset) * loadImage(aBytes, addrLoad, addrExec, addrInit, fStart)
* *
* If the array contains a PAPER tape image in the "Absolute Format," load it as specified * If the array contains a PAPER tape image in the "Absolute Format," load it as specified
* by the format; otherwise, load it as-is using the address(es) supplied. * by the format; otherwise, load it as-is using the address(es) supplied.
@ -270,11 +270,12 @@ RAMPDP11.prototype.reset = function()
* @param {number|null} [addrLoad] * @param {number|null} [addrLoad]
* @param {number|null} [addrExec] (this CAN override any starting address INSIDE the image) * @param {number|null} [addrExec] (this CAN override any starting address INSIDE the image)
* @param {number|null} [addrInit] * @param {number|null} [addrInit]
* @param {boolean} [fReset] * @param {boolean} [fStart]
* @return {boolean} (true if loaded, false if not) * @return {boolean} (true if loaded, false if not)
*/ */
RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fReset) RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fStart)
{ {
var fStop = false;
var fLoaded = false; var fLoaded = false;
/* /*
* Data on tapes in the "Absolute Format" is organized into blocks; each block begins with * Data on tapes in the "Absolute Format" is organized into blocks; each block begins with
@ -343,7 +344,7 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fR
} }
if (!cbData) { if (!cbData) {
if (addr & 0x1) { if (addr & 0x1) {
this.cpu.stopCPU(); fStop = true;
} else { } else {
if (addrExec == null) addrExec = addr; if (addrExec == null) addrExec = addr;
} }
@ -375,7 +376,13 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fR
* image, but we know that the directions for that diagnostic say to "Start and Restart at 200", * image, but we know that the directions for that diagnostic say to "Start and Restart at 200",
* so we have manually inserted an "exec":128 in the JSON containing the image. * so we have manually inserted an "exec":128 in the JSON containing the image.
*/ */
if (addrExec != null) this.cpu.setReset(addrExec, fReset); if (addrExec == null || fStop) {
this.cpu.stopCPU();
fStart = false;
}
if (addrExec != null) {
this.cpu.setReset(addrExec, fStart);
}
} }
return fLoaded; return fLoaded;
}; };

View file

@ -65,7 +65,7 @@ function RK11(parms)
* We record any 'autoMount' object now, but we no longer parse it until initBus(), * We record any 'autoMount' object now, but we no longer parse it until initBus(),
* because the Computer's getMachineParm() service may have an override for us. * because the Computer's getMachineParm() service may have an override for us.
*/ */
this.configMount = parms['autoMount'] || {}; this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0; this.cAutoMount = 0;
/* /*
@ -88,6 +88,30 @@ RK11.SOURCE = {
REMOTE: "??" REMOTE: "??"
}; };
/**
* parseConfig(config)
*
* @this {RK11}
* @param {*} config
* @return {*}
*/
RK11.prototype.parseConfig = function(config)
{
if (config && typeof config == "string") {
try {
/*
* The most likely source of any exception will be right here, where we're parsing
* this JSON-encoded data.
*/
config = eval("(" + config + ")");
} catch (e) {
Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
config = null;
}
}
return config || {};
};
/** /**
* setBinding(sType, sBinding, control, sValue) * setBinding(sType, sBinding, control, sValue)
* *
@ -143,7 +167,7 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "loadDrive": case "loadDisk":
this.bindings[sBinding] = control; this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) { control.onclick = function onClickLoadDrive(event) {
@ -156,7 +180,15 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "saveDrive": case "bootDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickBootDisk(event) {
rk11.bootSelectedDisk();
};
return true;
case "saveDisk":
/* /*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference * Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there * to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@ -201,7 +233,7 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "mountDrive": case "mountDisk":
if (!this.fLocalDisks) { if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available"); if (DEBUG) this.log("Local disk support not available");
/* /*
@ -263,21 +295,7 @@ RK11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.cpu = cpu; this.cpu = cpu;
this.dbg = dbg; this.dbg = dbg;
var configMount = this.cmp.getMachineParm('autoMount'); var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
if (configMount) {
if (typeof configMount == "string") {
try {
/*
* The most likely source of any exception will be right here, where we're parsing
* this JSON-encoded data.
*/
configMount = eval("(" + configMount + ")");
} catch (e) {
Component.error(this.type + " auto-mount error: " + e.message + " (" + configMount + ")");
configMount = null;
}
}
}
/* /*
* Add only drives from the machine-wide autoMount configuration that match drives managed by this component. * Add only drives from the machine-wide autoMount configuration that match drives managed by this component.
@ -527,6 +545,33 @@ RK11.prototype.loadSelectedDrive = function(sDiskName, sDiskPath, file)
this.loadDrive(iDrive, sDiskName, sDiskPath, false, file); this.loadDrive(iDrive, sDiskName, sDiskPath, false, file);
}; };
/**
* bootSelectedDisk()
*
* @this {RK11}
*/
RK11.prototype.bootSelectedDisk = function()
{
var drive;
var controlDrives = this.bindings["listDrives"];
var iDrive = controlDrives && str.parseInt(controlDrives.value, 10);
if (iDrive == null || iDrive < 0 || iDrive >= this.aDrives.length || !(drive = this.aDrives[iDrive])) {
this.notice("Unable to boot the selected drive");
return;
}
if (!drive.disk) {
this.notice("No disk loaded in the selected drive");
return;
}
var err = this.readData(drive, 0, 0, 0, drive.cbSector >> 1, 0);
if (err) {
this.notice("Unable to read the boot sector (" + err + ")");
return;
}
this.cpu.setReset(0, true);
};
/** /**
* loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file) * loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file)
* *
@ -639,7 +684,7 @@ RK11.prototype.finishLoadDrive = function onLoadDrive(drive, disk, sDiskName, sD
* With the addition of notify(), users are now "alerted" whenever a disk has finished loading; * With the addition of notify(), users are now "alerted" whenever a disk has finished loading;
* notify() is selective about its output, using print() if a print window is open, alert() otherwise. * notify() is selective about its output, using print() if a print window is open, alert() otherwise.
*/ */
this.notice("Mounted disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount); this.notice("Loaded disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
/* /*
* Since you usually want the Computer to have focus again after loading a new disk, let's try automatically * Since you usually want the Computer to have focus again after loading a new disk, let's try automatically
@ -941,6 +986,7 @@ RK11.prototype.processCommand = function()
case PDP11.RK11.FUNC.WRITE: case PDP11.RK11.FUNC.WRITE:
if (!sFunc) sFunc = "WRITE"; if (!sFunc) sFunc = "WRITE";
if (!fnReadWrite) fnReadWrite = this.writeData;
iCylinder = (this.regRKDA & PDP11.RK11.RKDA.CA) >> PDP11.RK11.RKDA.SHIFT.CA; iCylinder = (this.regRKDA & PDP11.RK11.RKDA.CA) >> PDP11.RK11.RKDA.SHIFT.CA;
iHead = (this.regRKDA & PDP11.RK11.RKDA.HS) >> PDP11.RK11.RKDA.SHIFT.HS; iHead = (this.regRKDA & PDP11.RK11.RKDA.HS) >> PDP11.RK11.RKDA.SHIFT.HS;
@ -950,8 +996,6 @@ RK11.prototype.processCommand = function()
if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") @" + str.toOct(addr) + "-" + str.toOct(addr + ((nWords - 1) << 1)), true); if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") @" + str.toOct(addr) + "-" + str.toOct(addr + ((nWords - 1) << 1)), true);
if (!fnReadWrite) fnReadWrite = this.writeData;
if (iCylinder >= drive.nCylinders) { if (iCylinder >= drive.nCylinders) {
this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXC; this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXC;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR; this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
@ -1023,9 +1067,9 @@ RK11.prototype.endReadWrite = function(err, iCylinder, iHead, iSector, nWords, a
* @param {number} iSector * @param {number} iSector
* @param {number} nWords * @param {number} nWords
* @param {number} addr * @param {number} addr
* @param {boolean} fCheck * @param {boolean} [fCheck]
* @param {function(...)} done * @param {function(...)} [done]
* @return {boolean} true if complete, false if queued * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/ */
RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done) RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done)
{ {
@ -1084,7 +1128,7 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
} }
} }
} }
return done(err, iCylinder, iHead, iSector, nWords, addr); return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
}; };
/** /**
@ -1097,9 +1141,9 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
* @param {number} iSector * @param {number} iSector
* @param {number} nWords * @param {number} nWords
* @param {number} addr * @param {number} addr
* @param {boolean} fCheck * @param {boolean} [fCheck]
* @param {function(...)} done * @param {function(...)} [done]
* @return {boolean} true if complete, false if queued * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/ */
RK11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done) RK11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done)
{ {
@ -1157,7 +1201,7 @@ RK11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, ad
} }
} }
} }
return done(err, iCylinder, iHead, iSector, nWords, addr); return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
}; };
/** /**

View file

@ -67,7 +67,7 @@ function RL11(parms)
* We record any 'autoMount' object now, but we no longer parse it until initBus(), * We record any 'autoMount' object now, but we no longer parse it until initBus(),
* because the Computer's getMachineParm() service may have an override for us. * because the Computer's getMachineParm() service may have an override for us.
*/ */
this.configMount = parms['autoMount'] || {}; this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0; this.cAutoMount = 0;
/* /*
@ -90,6 +90,30 @@ RL11.SOURCE = {
REMOTE: "??" REMOTE: "??"
}; };
/**
* parseConfig(config)
*
* @this {RL11}
* @param {*} config
* @return {*}
*/
RL11.prototype.parseConfig = function(config)
{
if (config && typeof config == "string") {
try {
/*
* The most likely source of any exception will be right here, where we're parsing
* this JSON-encoded data.
*/
config = eval("(" + config + ")");
} catch (e) {
Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
config = null;
}
}
return config || {};
};
/** /**
* setBinding(sType, sBinding, control, sValue) * setBinding(sType, sBinding, control, sValue)
* *
@ -145,7 +169,7 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "loadDrive": case "loadDisk":
this.bindings[sBinding] = control; this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) { control.onclick = function onClickLoadDrive(event) {
@ -158,7 +182,15 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "saveDrive": case "bootDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickBootDisk(event) {
rl11.bootSelectedDisk();
};
return true;
case "saveDisk":
/* /*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference * Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there * to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@ -203,7 +235,7 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
}; };
return true; return true;
case "mountDrive": case "mountDisk":
if (!this.fLocalDisks) { if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available"); if (DEBUG) this.log("Local disk support not available");
/* /*
@ -265,21 +297,7 @@ RL11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.cpu = cpu; this.cpu = cpu;
this.dbg = dbg; this.dbg = dbg;
var configMount = this.cmp.getMachineParm('autoMount'); var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
if (configMount) {
if (typeof configMount == "string") {
try {
/*
* The most likely source of any exception will be right here, where we're parsing
* this JSON-encoded data.
*/
configMount = eval("(" + configMount + ")");
} catch (e) {
Component.error(this.type + " auto-mount error: " + e.message + " (" + configMount + ")");
configMount = null;
}
}
}
/* /*
* Add only drives from the machine-wide autoMount configuration that match drives managed by this component. * Add only drives from the machine-wide autoMount configuration that match drives managed by this component.
@ -529,6 +547,33 @@ RL11.prototype.loadSelectedDrive = function(sDiskName, sDiskPath, file)
this.loadDrive(iDrive, sDiskName, sDiskPath, false, file); this.loadDrive(iDrive, sDiskName, sDiskPath, false, file);
}; };
/**
* bootSelectedDisk()
*
* @this {RL11}
*/
RL11.prototype.bootSelectedDisk = function()
{
var drive;
var controlDrives = this.bindings["listDrives"];
var iDrive = controlDrives && str.parseInt(controlDrives.value, 10);
if (iDrive == null || iDrive < 0 || iDrive >= this.aDrives.length || !(drive = this.aDrives[iDrive])) {
this.notice("Unable to boot the selected drive");
return;
}
if (!drive.disk) {
this.notice("No disk loaded in the selected drive");
return;
}
var err = this.readData(drive, 0, 0, 0, drive.cbSector >> 1, 0);
if (err) {
this.notice("Unable to read the boot sector (" + err + ")");
return;
}
this.cpu.setReset(0, true);
};
/** /**
* loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file) * loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file)
* *
@ -639,7 +684,7 @@ RL11.prototype.finishLoadDrive = function onLoadDrive(drive, disk, sDiskName, sD
* With the addition of notify(), users are now "alerted" whenever a disk has finished loading; * With the addition of notify(), users are now "alerted" whenever a disk has finished loading;
* notify() is selective about its output, using print() if a print window is open, alert() otherwise. * notify() is selective about its output, using print() if a print window is open, alert() otherwise.
*/ */
this.notice("Mounted disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount); this.notice("Loaded disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
/* /*
* Since you usually want the Computer to have focus again after loading a new disk, let's try automatically * Since you usually want the Computer to have focus again after loading a new disk, let's try automatically
@ -901,8 +946,8 @@ RL11.prototype.initDrive = function(drive, iDrive, data)
*/ */
RL11.prototype.processCommand = function() RL11.prototype.processCommand = function()
{ {
var fnReadWrite;
var fInterrupt = true; var fInterrupt = true;
var fnReadWrite, sFunc = "";
var iDrive = (this.regRLCS & PDP11.RL11.RLCS.DS) >> PDP11.RL11.RLCS.SHIFT.DS; var iDrive = (this.regRLCS & PDP11.RL11.RLCS.DS) >> PDP11.RL11.RLCS.SHIFT.DS;
var drive = this.aDrives[iDrive]; var drive = this.aDrives[iDrive];
var disk = drive.disk; var disk = drive.disk;
@ -954,11 +999,14 @@ RL11.prototype.processCommand = function()
break; break;
case PDP11.RL11.FUNC.RDATA: case PDP11.RL11.FUNC.RDATA:
sFunc = "READ";
fnReadWrite = this.readData; fnReadWrite = this.readData;
/* falls through */ /* falls through */
case PDP11.RL11.FUNC.WDATA: case PDP11.RL11.FUNC.WDATA:
if (!sFunc) sFunc = "WRITE";
if (!fnReadWrite) fnReadWrite = this.writeData; if (!fnReadWrite) fnReadWrite = this.writeData;
iCylinder = this.regRLDA >> PDP11.RL11.RLDA.SHIFT.RW_CA; iCylinder = this.regRLDA >> PDP11.RL11.RLDA.SHIFT.RW_CA;
iHead = (this.regRLDA & PDP11.RL11.RLDA.RW_HS)? 1 : 0; iHead = (this.regRLDA & PDP11.RL11.RLDA.RW_HS)? 1 : 0;
iSector = this.regRLDA & PDP11.RL11.RLDA.RW_SA; iSector = this.regRLDA & PDP11.RL11.RLDA.RW_SA;
@ -966,12 +1014,11 @@ RL11.prototype.processCommand = function()
this.regRLCS |= PDP11.RL11.ERRC.HNF | PDP11.RL11.RLCS.ERR; this.regRLCS |= PDP11.RL11.ERRC.HNF | PDP11.RL11.RLCS.ERR;
break; break;
} }
addr = (((this.regRLBE & PDP11.RL11.RLBE.MASK)) << 16) | this.regRLBA; // 22 bit mode
nWords = (0x10000 - this.regRLMP) & 0xffff; nWords = (0x10000 - this.regRLMP) & 0xffff;
var pos = ((((iCylinder << 1) + iHead) * drive.nSectors) + iSector) * 128; addr = (((this.regRLBE & PDP11.RL11.RLBE.MASK)) << 16) | this.regRLBA; // 22 bit mode
if (DEBUG && (this.messageEnabled(MessagesPDP11.READ) || this.messageEnabled(MessagesPDP11.WRITE))) {
console.log((fnReadWrite == this.readData? "readData" : "writeData") + "(pos=" + pos + ",addr=" + str.toOct(addr) + ",bytes=" + (nWords * 2) + ")"); if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") @" + str.toOct(addr) + "-" + str.toOct(addr + ((nWords - 1) << 1)), true);
}
fInterrupt = fnReadWrite.call(this, drive, iCylinder, iHead, iSector, nWords, addr, this.endReadWrite.bind(this)); fInterrupt = fnReadWrite.call(this, drive, iCylinder, iHead, iSector, nWords, addr, this.endReadWrite.bind(this));
break; break;
@ -1021,8 +1068,8 @@ RL11.prototype.endReadWrite = function(err, iCylinder, iHead, iSector, nWords, a
* @param {number} iSector * @param {number} iSector
* @param {number} nWords * @param {number} nWords
* @param {number} addr * @param {number} addr
* @param {function(...)} done * @param {function(...)} [done]
* @return {boolean} true if complete, false if queued * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/ */
RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, done) RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, done)
{ {
@ -1091,7 +1138,7 @@ RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
console.log("checksum: " + (checksum|0)); console.log("checksum: " + (checksum|0));
} }
return done(err, iCylinder, iHead, iSector, nWords, addr); return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
}; };
/** /**
@ -1104,8 +1151,8 @@ RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
* @param {number} iSector * @param {number} iSector
* @param {number} nWords * @param {number} nWords
* @param {number} addr * @param {number} addr
* @param {function(...)} done * @param {function(...)} [done]
* @return {boolean} true if complete, false if queued * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/ */
RL11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, done) RL11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, done)
{ {
@ -1173,7 +1220,7 @@ RL11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, ad
console.log("checksum: " + (checksum|0)); console.log("checksum: " + (checksum|0));
} }
return done(err, iCylinder, iHead, iSector, nWords, addr); return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
}; };
/** /**

View file

@ -9,7 +9,7 @@
<manifest ref="/apps/pc/1981/visicalc/manifest.xml" disk="*"/> <manifest ref="/apps/pc/1981/visicalc/manifest.xml" disk="*"/>
<disk path="/pubs/pc/programming/Graphics_for_the_IBM_PC/programs/disk.json">BASIC Programs</disk> <disk path="/pubs/pc/programming/Graphics_for_the_IBM_PC/programs/disk.json">BASIC Programs</disk>
</control> </control>
<control type="button" binding="loadDrive" padRight="8px">Load</control> <control type="button" binding="loadDisk" padRight="8px">Load</control>
<control type="description" binding="descDisk" padRight="8px"/> <control type="description" binding="descDisk" padRight="8px"/>
<control type="file" binding="mountDrive"/> <control type="file" binding="mountDisk"/>
</fdc> </fdc>