Assembler (DEC PDP-11)
The assembly language of the DEC PDP-11, whose eight general registers and eight orthogonal addressing modes made it the minicomputer assembler people actually enjoyed writing, and the machine on which Unix and C grew up.
Created by Digital Equipment Corporation; the PDP-11 architecture was designed by Harold McFarland with Gordon Bell, Roger Cady and colleagues
PDP-11 assembly language is the assembler of the machine that taught a generation what a computer ought to look like. Eight interchangeable general registers, eight addressing modes that work with any register and almost any instruction, a program counter and stack pointer that are simply two of those registers, and memory-mapped I/O over a single bus: the result was an instruction set that programmers described as pleasant, a word rarely applied to assembly language. It is the language in which the first PDP-11 Unix kernel was written, the language DEC’s own operating systems were built in, and the language whose shape is still visible in the Motorola 68000 and in C.
History and Origins
The machine
DEC shipped the first PDP-11, the PDP-11/20, in 1970. The architecture was designed principally by Harold McFarland, working with Gordon Bell, Roger Cady and others; the team published their design rationale as “A New Architecture for Minicomputers — The DEC PDP-11” at the 1970 AFIPS Spring Joint Computer Conference. The PDP-11 Handbook documenting the 11/20 carries a 1969 copyright, and its chapter on addressing already refers to “PAL-11, the PDP-11 assembler” — the assembly language and the machine arrived together.
The name PAL, Program Assembly Language, was inherited from DEC’s PDP-8 line, but the language underneath it was new. Where the PDP-8 had a single accumulator and a 12-bit word, the PDP-11 offered eight 16-bit general registers and byte addressing, and the assembler’s notation was built to expose that symmetry rather than to hide it.
Three assemblers, one language
DEC’s PDP-11 assemblers came in a sequence, each a superset of the last:
| Assembler | Documented | Environment | What it added |
|---|---|---|---|
| PAL-11A | 1970 Handbook, Paper Tape Software System | Paper tape, 4K words of core, ASR-33 | Two- or three-pass absolute assembler, optional listing and alphabetical symbol table |
| PAL-11R | PAL-11R Assembler Programmer’s Manual, May 1971 | DOS-11 | Relocatable object output, used with the LINK-11 linker and LIBR-11 librarian |
| MACRO-11 | DOS MACRO-11 Assembler Programmer’s Manual, June 1972 | DOS-11, then RT-11, RSX-11, RSTS/E | Full macro facility, conditional assembly, program sections |
MACRO-11 is what most people mean by “PDP-11 assembly language”. It shipped with every DEC
PDP-11 operating system, and its successor on the VAX, VAX MACRO, kept the same statement
format and much of the same directive vocabulary. Unix on the PDP-11 went its own way with
a smaller assembler called as, structurally similar to DEC’s but with different syntax
and far fewer features.
The Unix connection
Dennis Ritchie’s own account is unusually specific. By 1970 the Unix project had earned a new PDP-11 — “among the first of its line delivered by DEC” — and three months passed before the disk arrived. Ritchie wrote a simple PDP-11 assembler in B; Thompson, still waiting for storage, recoded the Unix kernel and some basic commands in PDP-11 assembly language, using 12K bytes of the machine’s 24K for the operating system and the rest as a RAM disk. The essentials of C were complete by early 1973, and the kernel was rewritten in C that summer.
One story about this period is worth correcting because it is repeated so often. C’s ++
and -- operators are frequently said to exist because the PDP-11 had autoincrement and
autodecrement addressing. Ritchie explicitly denied it: “This is historically impossible,
since there was no PDP-11 when B was developed.” The real influence ran the other way
around and was deeper than syntax — the PDP-11’s byte addressing and 16-bit word exposed
the inadequacies of B’s single word-sized cell, and pushed Ritchie toward a typed language
with char and pointer arithmetic that scaled properly.
The Language
Registers
Eight 16-bit general registers, R0 through R7, with two of them given a hardware role:
| Register | Role |
|---|---|
| R0–R5 | General purpose: accumulators, index registers, list pointers |
| R6 (SP) | Hardware stack pointer, used by JSR, traps and interrupts |
| R7 (PC) | Program counter — and a fully general register, addressable by any addressing mode |
Making the PC a general register is the single most consequential decision in the design.
Immediate operands, absolute addresses and PC-relative addresses are not separate
addressing modes; they are ordinary register modes applied to R7. MOV #5,R0 is
autoincrement on the PC. That is also why position-independent code is idiomatic rather
than exotic on the PDP-11: an ordinary MOV TABLE,R0 assembles to PC-relative form and
keeps working wherever the program is loaded.
Addressing modes
Every instruction word carries a six-bit operand field split into a three-bit mode and a three-bit register number, so each mode works with each register:
| Syntax | Mode | Effective operand |
|---|---|---|
Rn | Register | The register itself |
@Rn or (Rn) | Register deferred | Memory at the address in Rn |
(Rn)+ | Autoincrement | Memory at Rn, then Rn stepped by 1 or 2 |
@(Rn)+ | Autoincrement deferred | Indirect through the word Rn points to, then Rn stepped |
-(Rn) | Autodecrement | Rn stepped back first, then used as the address |
@-(Rn) | Autodecrement deferred | As above, one more level of indirection |
X(Rn) | Index | Memory at X plus Rn, with X in the following word |
@X(Rn) | Index deferred | Indirect through X plus Rn |
Autoincrement and autodecrement were the deliberate answer to a weakness Bell identified in earlier minicomputers — the absence of hardware stack support. As he put it in the retrospective, “In the PDP-11, this was solved with the autoincrement/autodecrement addressing mechanism. This solution is unique to the PDP-11 and has proven to be exceptionally useful.”
Combine general registers, general modes and a PC that is just another register, and a small number of opcodes covers an unusual amount of ground. The canonical demonstration is the block copy inner loop:
| |
Statement format
MACRO-11 statements follow the usual four-field assembler layout, with a semicolon
introducing comments and radix 8 by default — a constant written 100 is octal 100,
decimal 64, and a decimal constant is written 100. with a trailing point.
| |
Directives begin with a dot: .TITLE, .ASCIZ for a zero-terminated string, .WORD and
.BYTE for data, .BLKW and .BLKB for reserved storage, .MCALL to pull system-call
macros out of the system macro library, .END to close the module. Local labels are
numeric with a dollar sign — 1$, 2$ — and are scoped between ordinary labels, which is
why PDP-11 listings are not littered with invented names for loop tops.
Instruction set shape
Instructions are one, two or three words and fall into a handful of regular families:
- Double operand:
MOV,CMP,ADD,SUB,BIT,BIC,BIS— source and destination, each with a full addressing mode. - Single operand:
CLR,INC,DEC,NEG,TST,COM, the rotates and shiftsROL,ROR,ASL,ASR, andSWABfor byte swapping. - Byte variants: most of the above take a
Bsuffix —MOVB,CLRB,CMPB— so byte and word code are written the same way. - Branches:
BRplus the signed, unsigned and simple conditional branches, all PC-relative with an eight-bit offset. - Subroutines:
JSRandRTS, with any register nominated as the linkage register, soJSR PC,SUBRis a plain call andJSR R5,SUBRis the conventional way to pass an in-line argument list. - Traps:
EMTandTRAP, the vehicle for operating-system calls, plusBPTandIOT.
Later processors extended the set rather than replacing it: SOB (subtract one and branch)
and MARK arrived with the mid-range models, EIS added hardware multiply and divide, and
optional floating-point units added their own instruction group.
Code Examples
Hello, world under RT-11
| |
.MCALL tells the assembler which system macros this module uses; .TTYOUT and .EXIT
expand to EMT instructions that trap into the RT-11 monitor. Under RT-11 the build and
run sequence is .MACRO HELLO, .LINK HELLO, .R HELLO.
Stack and subroutine conventions
| |
Push and pop are not instructions. They are the ordinary MOV instruction with
autodecrement and autoincrement addressing on R6, which is why the PDP-11 supports
arbitrarily many stacks: any register can be a stack pointer, and the same two modes make
it one.
Byte counting loop
| |
Evolution
The instruction set grew outward from the 11/20 for twenty years without ever breaking its
shape. Memory management arrived soon after the original design — Bell wrote that it was
“extremely embarassing” [sic] that the PDP-11 “had to be redesigned with memory management
only two years after writing the paper that outlined the goal of providing increased address
space”, and
identified the shortage of address bits as the classic unrecoverable design mistake. The
mid-range models added SOB, MARK, XOR and the extended and floating instruction sets.
The LSI-11 of February 1975 compressed the processor onto four Western Digital LSI chips,
and the J-11, developed around 1979, onto two or three, carrying PDP-11 assembly into embedded control
applications that the 11/20’s designers never imagined.
The language then propagated in two directions. DEC’s own 32-bit successor, the VAX-11 announced in 1977, kept a PDP-11 compatibility mode in its early processors and gave the VAX an assembler, VAX MACRO, that is recognisably MACRO-11’s descendant. Outside DEC, the PDP-11’s register-and-mode orthogonality became the template other architects copied: Motorola’s 68000 is the case most often cited, and the PDP-11’s convention of mapping device registers into the memory address space, instead of providing separate I/O instructions, became standard practice in much of later microprocessor design.
Current Relevance
DEC stopped building PDP-11s in 1997, three years after selling the system-software rights to Mentec, and the last models of the line — the single-board 11/93 and 11/94 — dated from 1990. But PDP-11 assembly did not stop being written:
- Industrial and safety-critical installations kept running long past the hardware’s commercial life. In 2013 GE’s Canadian operation was reported to be recruiting a PDP-11 assembly programmer on vintage computing forums to maintain nuclear plant control systems, with the industry’s commitment to the hardware reported as running to 2050.
- Simulation is mature. SIMH and similar simulators boot original RT-11, RSX-11 and 2.11BSD images, and DEC-era operating system distributions and manuals are archived and freely available.
- Modern toolchains still target the machine. GCC documents a set of PDP-11 options and
the GNU assembler has a PDP-11 dependent-features section — the binutils target is
conventionally written
pdp11-aout— so it is possible to cross-assemble and cross-compile on a laptop and run the result under simulation or on real hardware. - Clone hardware keeps a second community alive. The Soviet-designed Elektronika BK and DVK machines implemented the PDP-11 instruction set, and BK demoscene productions are reportedly still written in PDP-11 assembly.
For anyone learning assembly language today, the PDP-11 remains one of the best teaching architectures in existence: small enough that the whole instruction set fits on a page, regular enough that there are almost no special cases to memorise, and historically central enough that what you learn explains the machines that came after it.
Why It Matters
The PDP-11 is the point where assembly language stopped being a per-machine idiosyncrasy and started being a discipline with a recognisable common shape. Around 600,000 PDP-11s of all models are commonly reported to have been sold, making it one of DEC’s most successful product lines, and a great many of the people who learned to program in the 1970s learned on this instruction set.
Its influence is structural rather than decorative. The idea that registers should be interchangeable, that addressing modes should compose freely with instructions, that the program counter and stack pointer are registers rather than special hardware, that device registers live in the memory map — all of these are PDP-11 arguments that were won so completely they now look like the natural order of things. And because Unix and C were built on this machine, in this language, the PDP-11’s assumptions about bytes, words, pointers and stacks were carried into software that long outlived the hardware and is still running everywhere today.
Timeline
Notable Uses & Legacy
Unix at Bell Labs
The first PDP-11 Unix kernel and its basic commands were written by Ken Thompson entirely in PDP-11 assembly language in 1970, and First Edition Unix (manual dated November 1971) was still an assembly-language system. Even after the 1973 C rewrite, the machine-dependent floor of the kernel stayed in assembler.
DEC's own operating systems
RT-11, RSX-11 and RSTS/E were written and maintained in MACRO-11, and shipped it as the system assembler. DEC's user-mode system calls were themselves macros (.TTYOUT, .EXIT and the rest) that expanded into EMT trap instructions.
Laboratory, instrument and process control
The LSI-11 and later Q-bus boards made PDP-11 assembly a standard language for data acquisition and real-time control, where hand-written interrupt service routines were the customary way to meet tight timing budgets. Published head-to-head benchmarks against the compilers of the period are not readily available, so the advantage is best treated as contemporary practice rather than a measured figure.
Nuclear plant control systems
PDP-11-based control systems remained in service in nuclear power plants long after DEC stopped building the hardware. In 2013 GE's Canadian operation was reported to be recruiting a PDP-11 assembly programmer on vintage-computing forums to maintain them, with the industry's commitment to the hardware reported as extending to 2050.
Soviet and Eastern Bloc PDP-11 clones
The SM EVM minicomputers and the Elektronika BK and DVK machines implemented the PDP-11 instruction set, so PDP-11 assembly became the low-level language of a whole parallel computing culture — and is reportedly still the language of the BK demoscene.
Preservation and emulation
SIMH and similar simulators run original PDP-11 operating systems on modern hosts, and the GNU toolchain still covers the architecture — GCC documents PDP-11 options and the GNU assembler has a PDP-11 dependent-features section (the binutils target is conventionally written `pdp11-aout`) — so PDP-11 assembly can still be written, assembled and executed today.