Skip to content
This repository has been archived by the owner on Dec 24, 2020. It is now read-only.

Commit

Permalink
Added remaining PDP11 CPU code, along with support for custom sprintf…
Browse files Browse the repository at this point in the history
…() format types
  • Loading branch information
jeffpar committed Nov 16, 2019
1 parent 7228152 commit 7072593
Show file tree
Hide file tree
Showing 56 changed files with 29,599 additions and 3,715 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

[modules/**.js]
[*.js]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
Expand Down
78 changes: 48 additions & 30 deletions _data/machines.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
"overview": [
"The top-level keys in machines.json are unique machine types; they are are used to form the names of the",
"compiled js packages; exceptions include any type beginning with an underscore (eg, '_JSONDoc') and 'shared',",
"which contains properties common to all the pre-v2.0 machines.",
"which contains properties common to all the pre-v2.00 machines.",
"",
"The next two properties, 'name' and 'class', define the external (displayed) name of the machine (eg, 'PCx86')",
"and the internal name (eg, 'pcx86'). The internal name is used as a prefix for the machine's CSS classes, and",
"a few other things, like the name of the versioned folder where all the compiled file(s) are packaged. For pre-v2.0",
"machines that used XSL templates, these properties are also propagated to the APPNAME and APPCLASS XSL variables.",
"'name' defines the external (displayed) name of the machine (eg, 'PCx86'); for pre-v2.00 machines that use XSL",
"template files, it is also propagated to the APPNAME XSL variable.",
"",
"Next, you may see a 'copy' property, which can be used by v2.0+ machines to refer to another machine configuration",
"that will be used for all other machine properties; it saves a bit repetition for machines that are very similar."
"'class' is only used with pre-v2.00 machines: it defines an internal name that's used as a prefix for the",
"machine's CSS classes, as well as the name of the versioned folder where all the compiled file(s), CSS files,",
"and XSL files are deposited; it is also propagated to the APPCLASS XSL variable.",
"",
"'copy' is an optional property used by new machines to refer to another machine configuration that will be used",
"for all other machine properties; it saves a bit repetition for machines that are very similar.",
"",
"'scripts' is a list of all the JavaScript files that comprise the machine; PCjs 'gulp' tasks will concatenate and",
"compile the files in the order listed, and if the web server is configured to load uncompiled files, they will also",
"be loaded on their respective web pages in the order listed."
],
"rant": [
"This section is here merely to vent my frustrations with JSON's stubborn and inflexible design, which has declared",
"that things like comments and hexadecimal constants are forbidden. I've read many conversations about this on",
"stackoverflow.com, and the Crockford apologists are completely unpersuasive. The main rationalization is that JSON",
"wss designed purely for machine interchange (ie, it's not meant to be consumed by humans), ignoring the fact that",
"was designed purely for machine interchange (ie, it's not meant to be consumed by humans), ignoring the fact that",
"humans must edit JSON files all the time. Even Crockford's own explanation for why he banned comments is a tacit",
"acknowledgement of that ('I removed comments from JSON because I saw people were using them to hold parsing directives,",
"a practice which would have destroyed interoperability.'). Other people say 'Hey, you should have foreseen that",
Expand Down Expand Up @@ -98,7 +104,6 @@
},
"leds": {
"name": "LEDs",
"class": "leds",
"version": "2.00",
"defines": [
"FACTORY",
Expand All @@ -119,12 +124,9 @@
"./modules/devices/main/led.js",
"./modules/devices/main/time.js",
"./modules/devices/cpu/cpu.js",
"./modules/devices/cpu/ledcpu.js",
"./modules/devices/cpu/ledctrl.js",
"./modules/devices/main/machine.js"
],
"styles": [],
"css": [],
"xsl": []
]
},
"pc8080": {
"name": "PC8080",
Expand Down Expand Up @@ -317,17 +319,14 @@
},
"ti42": {
"name": "TI42",
"class": "ti42",
"copy": "ti57"
},
"ti55": {
"name": "TI55",
"class": "ti55",
"copy": "ti57"
},
"ti57": {
"name": "TI57",
"class": "ti57",
"version": "2.00",
"defines": [
"FACTORY",
Expand All @@ -350,14 +349,10 @@
"./modules/devices/cpu/cpu.js",
"./modules/devices/cpu/cpu1500.js",
"./modules/devices/main/machine.js"
],
"styles": [],
"css": [],
"xsl": []
]
},
"invaders": {
"name": "Space Invaders",
"class": "invaders",
"version": "2.00",
"defines": [
"FACTORY",
Expand Down Expand Up @@ -387,14 +382,10 @@
"./modules/devices/cpu/debugger.js",
"./modules/devices/cpu/dbg8080.js",
"./modules/devices/main/machine.js"
],
"styles": [],
"css": [],
"xsl": []
]
},
"vt100": {
"name": "VT100",
"class": "vt100",
"version": "2.00",
"defines": [
"FACTORY",
Expand Down Expand Up @@ -426,9 +417,36 @@
"./modules/devices/cpu/debugger.js",
"./modules/devices/cpu/dbg8080.js",
"./modules/devices/main/machine.js"
]
},
"pdp11v2": {
"name": "PDP-11",
"version": "2.00",
"defines": [
"FACTORY",
"VERSION"
],
"styles": [],
"css": [],
"xsl": []
"folder": "devices",
"factory": "PDP11",
"scripts": [
"./modules/devices/lib/defs.js",
"./modules/devices/lib/numio.js",
"./modules/devices/lib/stdio.js",
"./modules/devices/lib/webio.js",
"./modules/devices/main/device.js",
"./modules/devices/main/input.js",
"./modules/devices/main/led.js",
"./modules/devices/main/time.js",
"./modules/devices/bus/bus.js",
"./modules/devices/bus/memory.js",
"./modules/devices/bus/ports.js",
"./modules/devices/bus/ram.js",
"./modules/devices/bus/rom.js",
"./modules/devices/cpu/cpu.js",
"./modules/devices/cpu/pdp11ops.js",
"./modules/devices/cpu/pdp11.js",
"./modules/devices/cpu/debugger.js",
"./modules/devices/main/machine.js"
]
}
}
164 changes: 164 additions & 0 deletions _posts/2019-11-11-creating-new-machines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
layout: post
title: Creating New Machines
date: 2019-11-11 10:00:00
permalink: /blog/2019/11/11/
---

The easiest way to create a new PCjs machine is to start with an old one. That's what I recently did for a pair
of 8080-based machines: [Space Invaders](/devices/pc8080/machine/invaders/new/) and the
[DEC VT100 Terminal](/devices/pc8080/machine/vt100/new/). There's nothing particularly exciting about these new machines,
other than they are easier to configure, embed, and maintain than my earlier [PC8080](/modules/pc8080/) versions.

In honor of the 8080, there are few more 8080-based machines I'd like to build soon, such as the
[MITS Altair 8800](https://livingcomputers.org/Computer-Collection/Vintage-Computers/Microcomputers/MITS-Altair-8800.aspx),
and I want to add Z-80 functionality so that I can support more classic PCs like the
[TRS-80](https://livingcomputers.org/Computer-Collection/Vintage-Computers/Microcomputers/TRS-80.aspx) as well as arcade
machines like [Galaxian](https://en.wikipedia.org/wiki/Galaxian).

However, at the moment, I need to switch gears and make a new PDP-11-based machine. More on *why* I need to do that later.

## First Steps

I started by adding a new entry for the machine to the PCjs machine "catalog" in [machines.json](https://github.com/jeffpar/pcjs/blob/master/_data/machines.json).

For this new PDP-11 machine, I simply copied the lines from the "vt100" machine, edited them a bit, and pasted them:

"pdp11v2": {
"name": "PDP-11",
"version": "2.00",
"defines": [
"FACTORY",
"VERSION"
],
"folder": "devices",
"factory": "PDP11",
"scripts": [
"./modules/devices/lib/defs.js",
"./modules/devices/lib/numio.js",
"./modules/devices/lib/stdio.js",
"./modules/devices/lib/webio.js",
"./modules/devices/main/device.js",
"./modules/devices/main/input.js",
"./modules/devices/main/led.js",
"./modules/devices/main/time.js",
"./modules/devices/bus/bus.js",
"./modules/devices/bus/memory.js",
"./modules/devices/bus/ports.js",
"./modules/devices/bus/ram.js",
"./modules/devices/bus/rom.js",
"./modules/devices/cpu/cpu.js",
"./modules/devices/cpu/debugger.js",
"./modules/devices/main/machine.js"
]
}

Every machine key must be unique, and since there was already an older machine with key "pdp11", I chose "pdp11v2"
for the new PDP-11 machine. Each key is also known as the machine's *type*, which determines the name of the compiled
JavaScript module (eg, "pdp11v2.js") and how web pages indicate which machine to load (eg, "type: pdp11v2").

This new machine immediately compiled (`gulp compile/pdp11v2`), although it won't do anything useful, because its
CPU and Debugger consist only of base classes that don't contain any CPU-specific code.

Next, I needed to create a machine configuration file describing a particular PDP-11 configuration.
The [PDP-11/20 BASIC Demo (with Debugger)](/devices/pdp11/machine/1120/basic/debugger/) seemed like a nice simple machine
to replicate. Since that's an older (v1) PCjs machine that uses XML configuration files, let's take a peek at the primary
[XML file](/devices/pdp11/machine/1120/basic/debugger/machine.xml):

<machine id="test1120" type="pdp11" border="1" pos="center" background="default">
<name pos="center">PDP-11/20: 16Kb, PDP-11 BASIC, Debugger</name>
<computer id="computer" busWidth="16"/>
<cpu id="cpu" model="1120" cycles="6666667"/>
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp11/tapes/basic/DEC-11-AJPB-PB.json"/>
<device id="default" type="default"/>
<serial id="dl11" adapter="0" binding="print" upperCase="true"/>
<panel ref="/devices/pdp11/panel/test/debugger/terminal.xml"/>
<debugger id="debugger" base="8" messages="" commands=""/>
<device ref="/devices/pdp11/pc11/default.xml"/>
</machine>

I translated the critical pieces of information to the following [JSON file](/devices/pdp11/machine/1120/basic/debugger/new/pdp1120.json):

{
"pdp1120": {
"class": "Machine",
"type": "Computer",
"name": "PDP-11/20",
"version": 2.00,
"autoSave": false,
"autoStart": false
},
"clock": {
"class": "Time",
"cyclesPerSecond": 6666667
},
"bus": {
"class": "Bus",
"addrWidth": 16,
"dataWidth": 8
},
"cpu": {
"class": "PDP11",
"model": "KA11"
},
"ram": {
"class": "RAM",
"addr": 0,
"size": 16384
},
"debugger": {
"class": "DbgPDP11",
"_JSONDoc": [
"It's best to initialize the Debugger last, so that it can find any device it wants -- at the very least, the CPU."
]
}
}

At the moment, it's a very bare-bones machine with no I/O devices. The important properties are:

- 6666667 *cyclesPerSecond*
- RAM *size* of 16Kb at *addr* 0
- *autoSave* and *autoStart* disabled (preferred when debugging a new machine)

I now had enough pieces to create a [page](https://github.com/jeffpar/pcjs/blob/master/devices/pdp11/machine/1120/basic/debugger/new/README.md)
on which to run the machine. At the top of the page, I placed the following information:

---
layout: page
title: PDP-11/20 BASIC Demo with Debugger (New)
permalink: /devices/pdp11/machine/1120/basic/debugger/new/
machines:
- id: pdp1120
type: pdp11v2
config: pdp1120.json
---

Unfortunately, the page immediately crashed because although the "pdp11v2" machine type in machines.json indicated that
the machine's factory was "PDP11", I had neglected to add that new factory name to [machine.js](/modules/devices/main/machine.js):

window['PDP11'] = window[FACTORY];

Compiled machines have their factory name automatically hard-coded into the compiled code, but during early machine
development, I always run uncompiled code, with DEBUG-only code enabled. The PCjs node web server knows how to read
machines.json and serve all appropriate scripts for the specified machine type.

After relaoding the web page, the following call:

PDP11('pdp1120','pdp1120.json');

created the machine and generated the following console messages:

PCjs PDP-11/20 v2.00
Copyright © 2012-2019 Jeff Parsons <[email protected]>
License: GPL version 3 or later <http://gnu.org/licenses/gpl.html>
Configuration: pdp1120.json
unrecognized cpu device class: PDP11
unrecognized debugger device class: DbgPDP11
power on

which was to be expected, since as already noted, there is no CPU-specific (specifically, PDP11) code in the machine yet.

## Next Steps

*[@jeffpar](https://jeffpar.com)*
*November 11, 2019*
36 changes: 18 additions & 18 deletions devices/pc8080/machine/invaders/new/invaders.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,6 @@
}
}
},
"ports": {
"class": "InvadersPorts",
"bus": "busIO",
"addr": 0,
"size": 256,
"switches": {
"default": "11111111",
"11xxxxxx": "3 lives",
"01xxxxxx": "4 lives",
"10xxxxxx": "5 lives",
"00xxxxxx": "6 lives",
"xxx0xxxx": "Bonus life at 1000",
"xxx1xxxx": "Bonus life at 1500",
"xxxxxxx0": "Coin info off",
"xxxxxxx1": "Coin info on"
},
"bindings": ["sw1","sw2","sw3","sw4","sw5","sw6","sw7","sw8"]
},
"ram": {
"class": "RAM",
"addr": 8192,
Expand Down Expand Up @@ -651,6 +633,24 @@
34,252,34,205,228,1,205,127,26,205,141,8,205,214,9,0
]
},
"ports": {
"class": "InvadersPorts",
"bus": "busIO",
"addr": 0,
"size": 256,
"switches": {
"default": "11111111",
"11xxxxxx": "3 lives",
"01xxxxxx": "4 lives",
"10xxxxxx": "5 lives",
"00xxxxxx": "6 lives",
"xxx0xxxx": "Bonus life at 1000",
"xxx1xxxx": "Bonus life at 1500",
"xxxxxxx0": "Coin info off",
"xxxxxxx1": "Coin info on"
},
"bindings": ["sw1","sw2","sw3","sw4","sw5","sw6","sw7","sw8"]
},
"video": {
"class": "InvadersVideo",
"bus": "busMemory",
Expand Down
14 changes: 14 additions & 0 deletions devices/pdp11/machine/1120/basic/debugger/new/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
layout: page
title: PDP-11/20 BASIC Demo with Debugger (New)
permalink: /devices/pdp11/machine/1120/basic/debugger/new/
machines:
- id: pdp1120
type: pdp11v2
config: pdp1120.json
---

PDP-11/20 BASIC Demo with Debugger (New)
----------------------------------------

{% include machine.html id="pdp1120" %}
Loading

0 comments on commit 7072593

Please sign in to comment.