Programming the PDP-1
To read Spacewar! as code you have to know what kind of code it is. There was no operating system, no high-level language, no library to call. A program for the PDP-1 was a list of 18-bit words in the machine's own instruction set, written in octal or in the MACRO assembler's mnemonics, punched to paper tape and loaded into core. The game's physics, its controls and its glowing ships are all built from a few dozen instruction types operating on a single accumulator. This page is a short tour of that instruction set, and of the one instruction, dpy, that made the whole genre possible.1
Eighteen bits, octal, and one's complement
The PDP-1's word is 18 bits wide, conventionally written as six octal digits (each digit is three bits, so the largest word is 777777 octal). A memory-reference instruction divides that word into three fields: a five-bit operation code, a single indirect-address bit, and a twelve-bit address. Twelve bits is why the basic machine reaches exactly 4,096 words of core (00000 to 07777 octal); larger memories were addressed by switching in an extend mode.
| opcode | i | address | |||||||||||||||
| bits 0–4 · 5 bits | bit 5 | bits 6–17 · 12 bits → 4,096 words | |||||||||||||||
Arithmetic is one's complement: a negative number is the bitwise complement of its positive, which means the machine has two representations of zero (all-zeros and all-ones) and that overflow and sign behave a little differently from the two's-complement machines that came later. The programmer works mostly through one accumulator (AC), with an in-out register (IO) alongside it (the two can be joined for 36-bit shifts), a program counter (PC), an overflow flag, six program flags and a bank of sense switches on the console. A core cycle takes about 5.35 microseconds; most instructions take two cycles, roughly 10.7 microseconds, so the machine runs on the order of ninety thousand instructions a second. Every moving thing in Spacewar! has to be computed and drawn.
What the machine can be told to do
The instruction set is small enough to hold in your head: memory-reference instructions name a word to act on, while the operate, skip, shift and in-out groups are micro-coded bit-fields that combine in a single word. Type a mnemonic to look one up, the table filters as you go.
| Mnemonic | Octal | Instruction |
|---|
Mnemonic, the short name written in assembly (for example lac), standing in for the machine's numeric operation. Octal, that operation as a base-8 number, the way PDP-1 programmers wrote it (three bits per digit): two digits for memory-reference instructions, six for the micro-coded operate, skip, shift and in-out groups. Instruction, what it does, where AC is the accumulator, IO the in-out register, Y a memory location, and ← means "is given the value of".
The table loads sorted alphabetically by mnemonic. Click a column heading to sort by it (again to reverse, a third time to restore the original order). Instruction data after Norbert Landsteiner's PDP-1 instruction list and DEC's PDP-1 Handbook.
The whole game is points, plotted in a loop
One instruction matters more than all the others for this project. dpy, "display one point," takes the value in the accumulator as the point's X coordinate and the value in the IO register as its Y coordinate, and lights a single dot at that position on the Type 30 screen (a few bits select brightness). There is no line-drawing, no shape primitive, no frame buffer. A ship, a torpedo, a star, the heavy sun, every one of them is a set of points pushed through dpy, and they stay visible only because the program plots them again on the next pass and the phosphor holds the glow for a moment. Spacewar! at bottom is a loop: compute positions, load X into AC and Y into IO, dpy, repeat, fast enough that the eye reads motion.
Here is that idea in the game's own source. This is the dispt ("display point") macro from the 3.1 listing of September 1962, a definition in DEC's MACRO assembler:
Quoted from Spacewar! 3.1 (24 September 1962), held in our source archive. repeat 6, B=B+B doubles the brightness value six times, that is, shifts it left six bits, to seat it in the instruction's brightness field; lio loads the IO register; dpy then plots the point whose X coordinate the caller has already left in the accumulator.
It is worth pausing on the fact that this is a macro. DEC's MACRO assembler let the MIT programmers define their own higher-level operations, dispt, scale, diff, and build the game out of them, which is part of how a program this ambitious fitted in a few thousand words and stayed readable enough to be modified by a dozen hands. The assembler is itself part of the PDP-1 software the hackers wrote for themselves.
The instruction set is part of the meaning
Reading Spacewar! closely means reading at this level. The 18-bit word fixes the precision of the orbital arithmetic; one's-complement sign handling shows up in the physics; the single accumulator dictates a style of code that constantly loads, operates and stores; and dpy is the reason the game is a redraw loop rather than a picture.
1 The complete reference is Norbert Landsteiner's PDP-1 instruction list (masswerk.at). ↩
References
- Norbert Landsteiner, PDP-1 instruction list and the Inside Spacewar! series, masswerk.at, for the instruction set and octal codes.
- DEC, PDP-1 handbooks and the PDP-1 machine page here, for the word format, registers and cycle times.
- Spacewar! 3.1 (24 September 1962), the source of the
disptmacro quoted above; held with the other listings on the versions and source page.