PDP-8/I · Volume 5
PDP-8/I — Volume 5 — Architecture II: the Instruction Set, Addressing, Auto-Index
Eight instructions, three bits to name them, and a fistful of microcoded tricks — how a computer with no LOAD, no STORE, and no SUBTRACT still does everything, and does it in twelve bits per word.
About This Volume
This is Volume 5 of the fourteen-volume deep dive into the PDP-8/I, and the second of the two architecture volumes. Volume 4 laid the substrate: the twelve-bit word, memory carved into 4K fields of thirty-two 128-word pages, the privileged zero page, and the tiny set of registers a programmer can actually see — one accumulator, one link bit, one program counter. We assume all of that here and build directly on it.
The job now is to put that substrate to work. A computer is not its registers; it is the set of operations it can perform on them, and the way those operations name the data they touch. This volume is about both. We will count the PDP-8’s instructions — there are exactly eight, because three bits can name eight things and the machine spends only three bits naming them — and discover that the list is missing things you would swear a computer cannot do without: there is no LOAD, no STORE, no SUBTRACT, no COMPARE. We will see how the machine does all of those anyway, from a smaller vocabulary, by composition. We will follow the seven-bit address field as it combines with the page bit and the indirect bit to reach any word in a 4,096-word field. We will meet the eight magic locations on page 0 that increment themselves. And we will take apart the strangest and most characteristic instruction of all — the operate instruction, which is not one instruction but a field of independent micro-operations the programmer combines, several to a word, like a tiny horizontal program baked into a single twelve-bit pattern. By the end you should be able to read any PDP-8 instruction word, octal digit by octal digit, and say exactly what it does.
The eight instructions
Recall the shape of an instruction word: twelve bits, numbered 0 through 11 from the left, bit 0 the most significant. The PDP-8 spends its three highest bits — bits 0, 1, and 2 — on the operation code, the field that says which instruction this word is. Three bits encode 2³ = eight values, octal 0 through 7, and so the PDP-8 has exactly eight instructions. Not eight families of dozens, as on a richer machine; eight, full stop. Here is the entire instruction set of the computer:
opcode (bits 0-2) mnemonic class what it does
+----------------+-----------+----------------+-------------------------------------+
| 000 octal 0 | AND | memory ref. | logical AND of memory word into AC |
| 001 octal 1 | TAD | memory ref. | two's-complement ADD into AC (+L) |
| 010 octal 2 | ISZ | memory ref. | increment memory word, skip if zero |
| 011 octal 3 | DCA | memory ref. | deposit AC to memory, then clear AC |
| 100 octal 4 | JMS | memory ref. | jump to subroutine (save return) |
| 101 octal 5 | JMP | memory ref. | jump |
| 110 octal 6 | IOT | input/output | in/out transfer to a device |
| 111 octal 7 | OPR | operate | microcoded register operations |
+----------------+-----------+----------------+-------------------------------------+
Six of the eight — opcodes 0 through 5 — are memory-reference instructions: each one names a word in memory and does something with it. The other two are special. Opcode 6, IOT, talks to the outside world. Opcode 7, OPR, does not touch memory at all; it operates on the registers directly, and it is microcoded in a way we will spend the back half of this volume on. First, though, look hard at the six memory-reference instructions, because the most instructive thing about them is what is not there.
There is no LOAD and no STORE — no instruction whose job is simply “copy this memory word into the accumulator” or “copy the accumulator into this memory word.” The modern programmer expects that pair as the bread and butter of any machine; the PDP-8 has neither by that name. There is no SUBTRACT. And there is no MULTIPLY or DIVIDE in the base machine at all. A computer, you might think, must surely be able to subtract. The PDP-8 cannot — not as a single instruction — and the way it gets along without is the key to the whole design philosophy.
Take loading first. To get a value out of memory and into the AC, the trick is to clear the accumulator to zero and then add. There is no LOAD, but there is TAD (add) and there is a way to clear the AC (a micro-op of the OPR instruction we will meet shortly), so “load” becomes clear, then add — two operations where another machine would have one. Storing is even tidier, and the PDP-8 builds it into a single instruction: DCA, Deposit and Clear Accumulator, writes the AC to a memory word and clears the AC in the same breath. That combination is not an accident. After you have stored a value you almost always want a fresh, empty accumulator for the next computation, and clearing it is exactly what you must do before the next “load-by-adding.” DCA does both, so the common pattern — compute a result, store it, start the next computation — flows naturally. The very absence of a plain STORE is what makes DCA the right shape.
Now subtraction. To compute A − B, the PDP-8 leans on the fact that subtraction is just addition of a negative, and that negating a two’s-complement number is a fixed little dance: complement all the bits, then add one. The machine can complement the accumulator (the CMA micro-op) and increment it (the IAC micro-op), and — this is the elegant part — both of those are micro-ops of the same OPR instruction, so it can do both in one word. That combined word even has its own conventional name, CIA (Complement and Increment Accumulator, literally CMA IAC), and it negates the AC in a single instruction. So A − B becomes: get B into the AC, CIA to make it −B, add A with TAD. The machine has no SUBTRACT because it does not need one — TAD plus the ability to negate covers it, at the cost of an extra instruction here and there.
This is the PDP-8’s entire bargain restated in the instruction set. Volume 4 showed it spending the fewest possible bits on word width and registers; here it spends the fewest possible bits on opcodes. Eight instructions is the smallest opcode field that still leaves a genuinely general-purpose machine, and everything the eight cannot do directly — load, subtract, compare, test — is built up by composing them. The programmer pays in instruction count and cleverness; DEC paid in less hardware and a lower price. It is the same thesis all the way down.
Three classes of instruction, three readings of twelve bits
The eight opcodes fall into three classes, and the classes matter because each class reads the remaining nine bits of the word completely differently. The same twelve bits mean one thing under a memory-reference opcode, another under IOT, and a third under OPR. The opcode is the lens; the lower bits are only meaningful once you know which lens you are looking through.
The three classes are:
- Memory-reference instructions (MRIs), opcodes 0 through 5 — AND, TAD, ISZ, DCA, JMS, JMP. Here the lower nine bits encode which memory word the instruction acts on, via the addressing scheme below.
- Input/output transfer, opcode 6 — IOT. Here the lower nine bits are split into a device-selector field and a set of operation pulses; they name a peripheral and tell it what to do. (The mechanics of I/O — device codes, the I/O pulses, the interrupt system — are the subject of a later volume; for now it is enough that opcode 6 hands the lower bits to the device-addressing logic rather than to the memory-addressing logic.)
- Operate, opcode 7 — OPR. Here the lower nine bits are not an address at all but a bank of individual switches, each enabling one micro-operation on the registers. This is the microcoded class, and we take it apart at length below.
For the rest of this section we are concerned only with the first class, the memory-reference instructions, because their bit layout is the heart of how the PDP-8 reaches its memory. An MRI spends its twelve bits like this:
Memory-reference instruction format (opcodes 0-5)
bit 0 1 2 3 4 5 6 7 8 9 10 11
+----+----+----+----+----+----+----+----+----+----+----+----+
| opcode | I | P | 7-bit page offset |
| (0..5) | | | (0 .. 177 octal) |
+----+----+----+----+----+----+----+----+----+----+----+----+
bits 0-2 b3 b4 bits 5 ............... 11
bit 3 = I : INDIRECT bit 0 = direct 1 = indirect
bit 4 = P : PAGE bit 0 = page 0 1 = current page
bits 5-11 : 7-bit OFFSET within the selected 128-word page
Three bits of opcode, then two single-bit modifiers, then a seven-bit address offset: 3 + 1 + 1 + 7 = 12, and the whole word is accounted for. The two modifier bits are the entire addressing system, and they are worth memorizing exactly. Bit 3 is the indirect bit, I. Bit 4 is the page bit, P. Bits 5 through 11 are the seven-bit offset. Get those three facts straight and PDP-8 addressing unfolds cleanly.
Addressing: seven bits reaching four thousand words
Here is the problem the format has to solve, restated from Volume 4. The offset field is only seven bits, and seven bits count to 2⁷ = 128. But a memory field holds 4,096 words. Seven bits cannot directly name 4,096 of anything; they can name 128. The page system, and the two modifier bits, are how the machine bridges that gap of thirty-two to one.
The page bit, P (bit 4), chooses which 128-word page the offset is measured into. A field is thirty-two pages of 128 words each. The seven-bit offset picks a word within a page — position 0 to 127 — and the page bit picks which page:
- P = 0 → the offset is taken within page 0, the zero page, words 0000–0177 octal. Every instruction in the field, wherever it physically lives, can reach into page 0 this way. That is what makes page 0 the shared common ground Volume 4 described.
- P = 1 → the offset is taken within the current page — the very page the executing instruction sits on. The high-order address bits are copied from the program counter, so “current page” means literally “this 128-word block.” An instruction on page 17 with P = 1 reaches another word on page 17.
So with one bit, a direct memory reference can reach either of two pages: page 0, or the page it is standing on. That is 256 directly reachable words from any point in the program — enough for an instruction’s own local data and the shared base page, which covers the overwhelming majority of references in real code. Working out the effective address from a direct MRI is a small, mechanical recipe:
Direct addressing (I = 0):
if P = 0: effective address = 0000 + offset (a word on page 0)
if P = 1: effective address = (PC's page) + offset (a word on this page)
A worked micro-example. Suppose the instruction at location 0405 octal (which is on page 2, since page 2 spans 0400–0577) is the bit pattern for TAD with I = 0, P = 1, offset = 0010 octal. TAD is opcode 1. P = 1 means current page, and the current page of location 0405 is page 2, base 0400. The effective address is 0400 + 0010 = 0410 octal. The instruction adds the contents of word 0410 into the accumulator. Had the same offset come with P = 0, the page base would be 0000 and the effective address would be 0010 — a different word entirely, down on the zero page. One bit, two pages.
But two pages is not all of memory. What about the other thirty pages — a table on page 5 referenced by code running on page 20? No combination of P and a seven-bit offset can name it directly. This is precisely where the indirect bit, I (bit 3), earns its place.
When I = 1, the word the offset points at is not the operand — it is the address of the operand. The processor first computes a direct address exactly as above (using the page bit to land on page 0 or the current page), then goes to that location and reads its full twelve-bit contents, and those twelve bits are the address it actually operates on. The seven-bit field in the instruction only has to reach a nearby pointer; the pointer, being a full word, can hold any address in the entire 4,096-word field. Indirection is the lever that turns a seven-bit reach into a twelve-bit reach:
Indirect addressing (I = 1):
1. form a direct address D from P and the offset (page 0 or current page)
2. read the full 12-bit word stored at D -> a pointer
3. the effective address is that pointer; operate on the word it names
The cost is an extra memory cycle — the machine reads the pointer, then reads the operand — but the reward is total reach. A program keeps a little table of pointers in places it can reach directly (the current page, or the shared zero page) and indirects through them to touch anything, anywhere in the field. The two bits together give the PDP-8 its full addressing repertoire: direct to page 0, direct to the current page, indirect via page 0, indirect via the current page. Four modes from two bits, and they are enough to address every word of memory from every point in the program. The seven-bit problem is solved.
The auto-index registers
Indirection through a pointer is powerful, but a great deal of real programming is not about touching one far-off word — it is about marching through a sequence of them: summing an array, copying a string, scanning a buffer. Done with plain indirection, every step of such a walk costs you the same chore: fetch the pointer, use it, increment it so it points at the next element, store it back. The increment-and-store is pure overhead, repeated on every element, and the PDP-8 has a beautiful little piece of hardware to make it vanish.
On page 0, the eight locations 0010 through 0017 octal — octal 10 through 17 — are the auto-index registers. They are ordinary memory words in every respect but one: when one of them is used as an indirect pointer, the hardware automatically increments its contents by one before using it. Not after — before. The processor reads the auto-index location, adds one to it, writes the incremented value back, and then uses that incremented value as the effective address. This is pre-increment indirection, and it is built into the memory cycle, costing the program nothing beyond the indirect reference it was going to make anyway.
The payoff is cheap pointer-walking. To step through an array, you set an auto-index register to point just before the first element (because the first use will pre-increment it onto the first element), and then each indirect reference through it both advances the pointer and delivers the next element, automatically. Here is the shape of a loop that sums a list:
Summing an array with an auto-index register (sketch)
set location 0010 = (address of first element) - 1 ; point one before
clear AC
LOOP:
TAD I 0010 ; indirect via 0010: hardware pre-increments 0010,
; then adds the word it now points at into AC
... test for end of list, e.g. with ISZ on a counter ...
JMP LOOP
... AC now holds the running sum ...
The single instruction TAD I 0010 does the work of four: advance the pointer, write it back, fetch the element, add it in. Each pass through the loop the pointer climbs by one with no explicit increment anywhere in sight — the increment is a side effect of the address range the pointer lives in. Eight such registers means a routine can walk eight independent sequences at once: copy a string from one auto-index source to another auto-index destination, merge two lists, and so on. The PDP-8 has no index registers in the conventional sense — no register you add to an address to compute a subscript — but these eight self-incrementing words are its substitute, and for the common case of sequential access they are arguably tidier than a general index register would be. It is a characteristic PDP-8 economy: rather than add an addressing mode and the hardware to support it, DEC gave eight ordinary memory locations one small magic property and let the existing indirect mechanism do the rest.
OPR: the microcoded operate instruction
We come now to opcode 7, OPR, the operate instruction, and to the cleverest idea in the architecture. The other seven opcodes each do one thing. OPR does not do “one thing” at all. It is better understood as a field of independent switches: each of the lower bits, when set, enables a particular micro-operation on the registers — clear the accumulator, complement it, rotate it, skip the next instruction, halt — and a single OPR word can have several of those switches set at once, performing several micro-operations together, in one instruction, in one memory cycle. The programmer is, in effect, writing a tiny horizontal microprogram into the low nine bits of the word and handing it to the hardware to execute in a defined order.
Because the bits act independently, the assembler lets you write an OPR instruction as a list of micro-op mnemonics, and it simply ORs their bit patterns together. CLA is one bit; CLL is another; writing CLA CLL sets both bits and clears the accumulator and the link in one instruction. This combining is the signature of the PDP-8: where another machine would need a clear-AC instruction and a clear-link instruction and two memory cycles to run them, the PDP-8 packs both into a single word. There is even an OPR word with no bits set — octal 7000, every switch off, which does nothing at all: that is the machine’s NOP.
The operate instruction is split into groups, distinguished by bit 3 (and, for the third group, bit 11). Group 1 handles clearing, complementing, incrementing, and rotating. Group 2 handles the conditional skips and a couple of special operations. A third group, the optional EAE, handles multiply and divide. We take them in turn.
Group 1: clear, complement, increment, rotate
A Group 1 OPR has bit 3 = 0. The remaining low bits each enable one operation on the AC and link:
OPR Group 1 format (opcode 7, bit 3 = 0)
bit 0 1 2 3 4 5 6 7 8 9 10 11
+----+----+----+----+----+----+----+----+----+----+----+----+
| 1 1 1 | 0 |CLA |CLL |CMA |CML |RAR |RAL | RT |IAC |
+----+----+----+----+----+----+----+----+----+----+----+----+
opcode = 7 grp | | | | | | | |
= 1 | | | | | | | +-- bit 11 IAC (7001)
| | | | | | +------- bit 10 "rotate twice"/BSW (7002)
| | | | | +------------ bit 9 RAL (7004)
| | | | +----------------- bit 8 RAR (7010)
| | | +---------------------- bit 7 CML (7020)
| | +--------------------------- bit 6 CMA (7040)
| +-------------------------------- bit 5 CLL (7100)
+------------------------------------- bit 4 CLA (7200)
CLA clear AC CLL clear link CMA complement AC CML complement link
IAC increment AC (with carry into link)
RAR/RAL rotate the 13-bit <L,AC> ring right/left one place
bit 10 set WITH RAR -> RTR (rotate twice right, 7012)
bit 10 set WITH RAL -> RTL (rotate twice left, 7006)
bit 10 set ALONE -> BSW (byte swap, 7002) on the later PDP-8/E; a no-op on the 8/I
What makes Group 1 more than a bag of switches is that the operations happen in a defined sequence of events, not all at once, so that combining them composes in a useful order. The sequence is:
- CLA, CLL — the clears happen first.
- CMA, CML — then the complements.
- IAC — then the increment.
- RAR, RAL, RTR, RTL, BSW — then the rotates, last.
This ordering is exactly what makes the negation idiom work. Recall CIA = CMA IAC: it complements the AC (step 2) and then increments it (step 3), which is precisely the complement-then-add-one recipe for two’s-complement negation. Because complement is defined to run before increment, the two micro-ops in one word produce −AC correctly. The order is not arbitrary; it is chosen so that the most useful combinations — clear-then-add-one to load the constant 1, complement-then-increment to negate, and so on — fall out naturally. The rotates coming last lets you, for example, clear the link, set up a value, and rotate it into a known state all in one word.
Group 2: the skips, OSR, and HLT
A Group 2 OPR has bit 3 = 1 (and bit 11 = 0, which distinguishes it from the third group). Group 2 is mostly about conditional skips — testing the AC and link and, if the test passes, skipping the next instruction. Skipping is how the PDP-8 makes decisions: a skip instruction followed by a JMP is the machine’s if-then. The Group 2 layout:
OPR Group 2 format (opcode 7, bit 3 = 1, bit 11 = 0)
bit 0 1 2 3 4 5 6 7 8 9 10 11
+----+----+----+----+----+----+----+----+----+----+----+----+
| 1 1 1 | 1 |CLA |SMA |SZA |SNL |s/o |OSR |HLT | 0 |
+----+----+----+----+----+----+----+----+----+----+----+----+
opcode = 7 grp | | | | | | |
= 2 | | | | | | +-- bit 10 HLT (7402)
| | | | | +------- bit 9 OSR (7404)
| | | | +------------ bit 8 skip sense (7410): 0 = OR, 1 = AND
| | | +----------------- bit 7 SNL/SZL (7420)
| | +---------------------- bit 6 SZA/SNA (7440)
| +--------------------------- bit 5 SMA/SPA (7500)
+-------------------------------- bit 4 CLA (7600)
With sense bit (8) = 0, the OR group, "skip if ANY condition true":
SMA skip if AC < 0 SZA skip if AC = 0 SNL skip if link != 0
With sense bit (8) = 1, the AND group, "skip if ALL conditions true":
SPA skip if AC >= 0 SNA skip if AC != 0 SZL skip if link = 0
OSR OR the front-panel switch register into AC
HLT halt the processor
Three test bits, and a fourth bit — bit 8, the skip-sense bit — that flips the meaning of the tests. With the sense bit clear (the OR group), the skip fires if any enabled condition is true: SMA skips on a negative AC, SZA on a zero AC, SNL on a nonzero link. With the sense bit set (the AND group), each test inverts and they combine with AND: SPA skips on an AC that is not negative, SNA on a nonzero AC, SZL on a zero link. The same three physical bits thus give six named skip instructions, OR-combined or AND-combined depending on bit 8 — another example of one bit doubling the vocabulary. Note that you may not freely mix an OR-sense and an AND-sense mnemonic in the same word, precisely because the single sense bit can only mean one thing at a time.
Beyond the skips, Group 2 carries two more operations. OSR ORs the twelve front-panel switch-register toggles into the accumulator — the readable hand-set input Volume 4 described — and HLT stops the processor. As in Group 1, the operations run in a defined order: the skips are evaluated first, then CLA clears the accumulator, then OSR and HLT. That order makes CLA OSR (clear, then OR in the switches) a clean “load the switch register into the AC” — the idiom DEC named LAS, load accumulator from switches. Once again a single OPR word does the work of two instructions, and the defined sequence is what makes the combination mean the sensible thing.
Group 3 / EAE: the optional arithmetic muscle
The base PDP-8/I, as noted, has no multiply or divide. For customers who needed real arithmetic horsepower, DEC offered the Extended Arithmetic Element (EAE), an option whose instructions form a third group of the operate class — bit 3 = 1 and bit 11 = 1. The EAE adds one new programmer-visible register, the MQ (Multiplier-Quotient), a twelve-bit companion to the accumulator, together with micro-ops to move data between AC and MQ (MQA, MQL) and the arithmetic instructions proper: MUY (multiply) and DVI (divide), which use the AC and MQ together to hold the double-length products and dividends that twelve-bit multiplication and division require. The EAE is genuinely optional — software on a base machine simply synthesizes multiply and divide from shifts and adds, bit by bit, using the Group 1 rotates and the link — but where it was fitted it turned the PDP-8 into a respectable number-cruncher. We mention it here only to complete the picture of opcode 7; its full operation belongs to a later volume.
Why this is the design’s signature
Step back and look at what the operate instruction accomplishes. With one opcode value out of eight, and nine bits of switches read in a defined order, the PDP-8 obtains its clears, its complements, its increment, its rotates, six conditional skips, a switch-register read, and a halt — and lets the programmer combine compatible ones several to a word. CLA CLL clears two registers in one cycle. CIA negates in one cycle. LAS reads the panel in one cycle. None of these needed a dedicated opcode; all of them fall out of microcoding the single OPR instruction. This is the same minimalism that gave the machine a twelve-bit word and a lone accumulator, now expressed at the level of the instruction set: rather than spend opcodes on operations, spend bits within one opcode on micro-operations and let the programmer assemble what they need. It is the PDP-8 doing the most with the very least, one more time — and it is why a computer with only eight instructions, no LOAD, no STORE, and no SUBTRACT is nonetheless complete, capable, and, even sixty years on, a small marvel to read. The foundation of Volume 4 and the instruction set of this volume together are very nearly the whole machine. From here the series turns from the abstract architecture to the iron that realized it.
Sources
- Doug Jones, “PDP-8 Microcoded Instructions” and the companion PDP-8 programming pages (University of Iowa). Primary source for the exact OPR Group 1 and Group 2 bit assignments and octal codes (CLA 7200, CLL 7100, CMA 7040, CML 7020, RAR 7010, RAL 7004, the rotate-twice/BSW bit 7002, IAC 7001; CLA 7600, SMA 7500, SZA 7440, SNL 7420, the OR/AND skip-sense bit 7410, OSR 7404, HLT 7402), the defined sequence of events within each group, the RTR/RTL/BSW combinations, the CIA = CMA IAC idiom, and the Group 3/EAE MQ-register instructions. https://homepage.cs.uiowa.edu/~jones/pdp8/man/micro.html · https://homepage.cs.uiowa.edu/~jones/pdp8/
- Wikipedia, “PDP-8.” Confirms the eight opcodes and their mnemonics (0 AND, 1 TAD, 2 ISZ, 3 DCA, 4 JMS, 5 JMP, 6 IOT, 7 OPR), the memory-reference instruction format (bits 0–2 opcode, bit 3 indirect, bit 4 page/zero-page, bits 5–11 seven-bit offset), the auto-index registers at locations 0010–0017 octal with pre-increment on indirect reference, and the absence of a dedicated LOAD/STORE/SUBTRACT in the base instruction set. https://en.wikipedia.org/wiki/PDP-8
- PiDP-8/I Software project, “PDP-8 Memory Addressing” (tangentsoft.com). Detailed treatment of the seven-bit offset, the page bit, direct versus indirect addressing, effective-address formation against page 0 versus the current page, and the auto-index mechanism. https://tangentsoft.com/pidp8i/wiki?name=PDP-8+Memory+Addressing
- Small Computer Handbook and PDP-8/I & PDP-8/L Users Handbook (Digital Equipment Corporation), via bitsavers.org. DEC’s own definitions of the instruction classes, the memory-reference format, the operate microinstruction groups, and the EAE option. http://www.bitsavers.org/pdf/dec/pdp8/
- “An Overview of PDP-8 Architecture” (Wittenberg University) and “PDP-8 architecture,” Computer History Wiki (gunkies.org). Corroborate the three instruction classes, the skip/OR-AND sense mechanism, and the role of OPR composition. http://www4.wittenberg.edu/academics/mathcomp/shelburne/comp255/notes/PDP8Overview.htm · https://gunkies.org/wiki/PDP-8_architecture