PDP-11 architecture
| Industry | Computer hardware |
|---|---|
| Founded | 1957 |
| Founder | Ken Olsen, Harlan Anderson |
| Headquarters | Maynard, Massachusetts , United States |
| Products | PDP-11, VAX architecture |
The PDP-11 architecture represents a 16-bit CISC instruction set architecture (ISA) created by Digital Equipment Corporation (DEC). It served as the foundation for the PDP-11 minicomputers, which were extensively utilized throughout the 1970s, before being replaced by the more sophisticated VAX architecture during the 1980s.
CPU registers
Note: Moving a byte into register sign-extends bits 8–15 (No byte variant) (No byte variant)
The processor contains eight 16-bit general-purpose registers labeled R0 through R7. Among these, R7 is designated as the program counter (PC), while R6 acts as the main stack pointer (SP) utilized for hardware interrupts and traps. Typically, R5 is used to reference the current procedure's call frame. Certain PDP-11 variants provide dual sets of registers R0 to R5 to optimize context switching performance. Additionally, the architecture implements distinct memory maps and stack pointers for Kernel, Supervisor, and User modes, thereby maintaining system integrity by segregating user-level processes from critical system functions. MemoryData formatsThe smallest addressable memory unit is the 8-bit byte, which can be stored in the lower halves of registers R0 through R5. 16-bit words are arranged in little-endian order, meaning the least significant byte is placed at the lower memory address, and these words are aligned on even addresses. Registers R0 through R7 can hold these words. Within the Extended Instruction Set (EIS), 32-bit double words are stored across pairs of registers and utilized by instructions such as MUL, DIV, and ASHC. Additional 32-bit data types include single-precision floating point numbers supported by the Floating Instruction Set (FIS) and the floating-point processor option (FPP), as well as long data types in the Commercial Instruction Set (CIS). Some of these employ a unique middle-endian format often called "PDP-endian." The FPP option also accommodates 64-bit double-precision floating-point formats. Memory managementThe PDP-11 system uses 16-bit addresses, enabling access to 64 KB of memory. Numeric constants are expressed in octal notation, and memory capacity is measured in words. Although the logical address space spans 32K words, the upper 4K physical addresses are reserved for I/O device mapping, resulting in a maximum usable memory size of 28K words (56 KB) on fully expanded configurations. The lowest memory addresses are dedicated to two-word vectors that store program counters and processor status for service routines invoked by interrupts or traps. These vectors manage program faults or system calls triggered by instructions such as BPT, EMT, IOT, or TRAP. Memory expansionBy 1975, the limitation imposed by the 16-bit logical address space became a constraint on system growth. To overcome this:
Addressing modesMost instructions specify an operand using six bits: three bits select one of eight addressing modes, while the other three bits identify a general-purpose register. The six-bit operand field is structured as follows:
In assembly language examples, Rn indicates registers R0 through R7. General register addressing modesThese eight addressing modes can be applied to any general register. However, their behavior differs when used with R6 (stack pointer) and R7 (program counter), which are explained separately.
In index addressing modes, X represents a 16-bit displacement provided by the instruction’s subsequent word. Double-operand instructions may employ these modes for both source and destination operands, resulting in three-word instruction length. Autoincrement and autodecrement operations adjust registers by one byte for byte-sized instructions and by two bytes for word-sized instructions. In deferred modes, adjustments are always two bytes because they reference word pointers. Program counter addressing modesUtilizing R7, the program counter, four addressing modes deliver essential capabilities:
Absolute addressing frequently identifies fixed memory locations such as input/output registers. Relative addressing is predominantly employed for variables and jump destinations within programs. When only relative modes are used, the code becomes position-independent, allowing for flexible relocation or loading without modifying addresses. Immediate and absolute modes correspond to autoincrement and autoincrement deferred applied to the PC; since PC points to words, it automatically advances by 2 bytes past additional words. Stack addressing modesR6, known as SP, functions as the hardware stack pointer for interrupts and traps, with the stack growing downward toward lower memory addresses. When these addressing modes are applied to SP or any software-managed stack pointer, their behavior is as follows:
SP always manages a word-oriented stack; autoincrement and autodecrement operations adjust SP by 2 bytes accordingly. Instruction setThe PDP-11 architecture supports both byte and word data operations. Bytes are addressed through either register low bytes or memory locations; words must reside at even memory addresses. Bit 15 in instruction encoding determines byte (set) or word (clear) operation mode. Byte instructions append a B suffix to mnemonics (e.g., MOVB). Certain instructions such as MARK and SOB were omitted on select models. Double-operand instructionsThe upper four bits of an instruction specify the opcode, while bit 15 indicates whether it operates on bytes or words. Source and destination addressing modes are each encoded in six-bit fields.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Certain two-operand instructions combine an addressing mode operand with an extra register operand:
| 15 | 9 | 8 | 6 | 5 | 3 | 2 | 0 | ||||||||
| Opcode | Register | Source/Destination | Register | ||||||||||||
Register pairs (Reg and Reg+1) store low and high parts of operands; Reg must be even except in MUL where odd Reg indicates no high part storage.
| Opcode | Mnemonic | Description |
|---|
|- !070 !! MUL !! Multiply operation: (Reg, Reg+1) ← Reg × Src |- !071 !! DIV !! Division operation: (Reg, Reg+1) ÷ Src; Reg ← quotient; Reg+1 ← remainder |- !072 !! ASH !! Arithmetic shift on Reg by Src<5:0>: left shift if positive, right if negative |- !073 !! ASHC !! Arithmetic shift on (Reg, Reg+1) by Src<5:0>: left if positive, right if negative |- !074 !! XOR !! Exclusive OR operation: Dest ← Dest ⊻ Reg
}
Single-operand instructions
The operation is determined by the upper ten bits, with bit 15 commonly used to select between byte and word addressing modes. The operand is identified by six bits.
| 15 | 6 | 5 | 3 | 2 | 0 | ||||||||||
| Opcode | Src/Dest | Register | |||||||||||||
| Opcode | Mnemonic | Description |
|---|---|---|
| 0001 | JMP | Jump to address: PC ← Src
|
| 0003 | SWAB | Swap bytes within word: Dest ← Swap-bytes(Dest)
|
| 0050 | CLR | Clear operation: Dest ← 0
|
| 1050 | CLRB | |
| 0051 | COM | Complement operation: Dest ← Ones-complement(Dest)
|
| 1051 | COMB | |
| 0052 | INC | Increment operation: Dest ← Dest + 1
|
| 1052 | INCB | |
| 0053 | DEC | Decrement operation: Dest ← Dest − 1
|
| 1053 | DECB | |
| 0054 | NEG | Negation operation: Dest ← Twos-complement(Dest)
|
| 1054 | NEGB | |
| 0055 | ADC | Add with carry: Dest ← Dest + C flag
|
| 1055 | ADCB | |
| 0056 | SBC | Subtract with carry: Dest ← Dest - C flag
|
| 1056 | SBCB | |
| 0057 | TST | Test operation: Set-flags(Src)
|
| 1057 | TSTB | |
| 0060 | ROR | Rotate right by one bit: Dest ← Rotate-right(Dest, 1)
|
| 1060 | RORB | |
| 0061 | ROL | Rotate left by one bit: Dest ← Rotate-left(Dest, 1)
|
| 1061 | ROLB | |
| 0062 | ASR | Arithmetic shift right by one bit: Dest ← Shift-right(Dest, 1)
|
| 1062 | ASRB | |
| 0063 | ASL | Arithmetic shift left by one bit: Dest ← Shift-left(Dest, 1)
|
| 1063 | ASLB |
| Opcode | Mnemonic | Description (continued) |
|---|
| 0064 | MTPS | Move to PSW register: PSW ← Src
|
|---|---|---|
| 0065 | MFPI | Push from previous I space onto stack: −(SP) ← Src
|
| 1065 | MFPD | Push from previous D space onto stack: −(SP) ← Src
|
| 0066 | MTPI | Pop into previous I space from stack: Dest ← (SP)+
|
| 1066 | MTPD | Pop into previous D space from stack: Dest ← (SP)+
|
| 0067 | SXT | Sign extend operation: If N flag ≠ 0 then Dest ← -1 else Dest ← 0
|
| 1067 | MFPS | Move from PSW register to destination: Dest ← PSW
|
Branch instructions
Branch operations depend on condition flags set by preceding CMP, BIT, TST instructions, or arithmetic and logical operations. Unlike Intel x86 architectures, MOV instructions also update condition codes, allowing branches based on zero or negative results.
The opcode occupies the high byte (bits 9 through 15), while bit 8 determines the branch condition. The lower byte contains a signed offset relative to the program counter, enabling both forward and backward jumps.
...| Opcode | C | Mnemonic | Condition or Description
... |
|---|
Because of the restricted branching range, developers frequently substituted the single-word BR instruction with a two-word JMP when targeting distant addresses. Conditional branches such as BEQ were often paired with BNE to work around this limitation.
The SOB (Subtract One and Branch) instruction decrements a register and performs a backward branch if the result is nonzero, utilizing a 6-bit offset.
...| Opcode | Mnemonic | Description
... |
|---|
Subroutine instructions
The JSR instruction initiates a subroutine call, utilizing six bits to define the addressing mode. It has the capability to preserve any register on the stack while loading it with the return address. Commonly, programs employ the PC register (e.g., JSR PC, address) and return using RTS PC.
For instance, executing JSR R4, address saves the current R4 value onto the stack and stores the return address in R4. Within the subroutine, inline data can be accessed through (R4)+ or pointers via @(R4)+, where autoincrement advances past these values. Such routines conclude with RTS R4.
The variant JSR PC,@(SP)+ swaps the PC with the top item on the stack, facilitating coroutine functionality. By placing a coroutine’s entry point on the stack, this instruction saves the current PC and jumps to that address. Coroutines can then exchange control and resume execution from where they previously paused by repeatedly invoking JSR PC,@(SP)+.
| 15 | 9 | 8 | 6 | 5 | 3 | 2 | 0 | ||||||||
| Opcode | Reg | Src | Register | ||||||||||||
| Opcode | Mnemonic | Operation |
|---|---|---|
| 004 | JSR | Jump to subroutine: -(SP) ← Reg; Reg ← PC; PC ← Src
|
The address stored in Reg after JSR is the instruction immediately following the JSR call.
| 15 | 3 | 2 | 0 | ||||||||||||
| Opcode | Reg | ||||||||||||||
| Opcode | Mnemonic | Operation |
|---|---|---|
| 00020 | RTS | Return from subroutine: PC ← Reg; Reg ← (SP)+
|
| 15
... |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colspan=10 style=background-color:#CCC; |Opcode | colspan=6 style=background-color:#9F9; |nn |
| Opcode | Mnemonic | Operation |
|---|---|---|
| 0064 | MARK | Return from subroutine discarding stack parameters:SP ← SP + (2 × nn), PC ← R5, R5 ← (SP)+
|
The MARK instruction removes parameters from the stack upon subroutine exit. The caller pushes R5 followed by up to 63 word-sized arguments, then executes MARK with the argument count. Before invoking the subroutine via JSR PC,address, SP is saved into R5. The subroutine finishes with RTS R5, which loads PC from R5 (pointing to MARK) and pops the caller’s return address into R5. Executing MARK adjusts SP to discard arguments and returns control flow. This instruction is infrequently used because its effect can be replicated by adding a value directly to SP.
Trap Instructions
| 15 | 9 | 8 | 7 | 0 | |||||||||||
| Opcode | S | Operation Code | |||||||||||||
| Opcode | S | Mnemonic | Description |
|---|---|---|---|
| 104 | 0 | EMT | Emulator trap sequence: -(SP) ← PS; -(SP) ← PC; PC ← (30); PS ← (32)
|
| 104 | 1 | TRAP | General trap sequence: -(SP) ← PS; -(SP) ← PC; PC ← (34); PS ← (36)
|
| 15 | 0 | ||||||||||||||
| Opcode | |||||||||||||||
| Opcode | Mnemonic | Description |
|---|---|---|
| 000002 | RTI | Return from interrupt routine: PC ← (SP)+; PS ← (SP)+
|
| 000003 | BPT | Breakpoint trap handling: -(SP) ← PS; -(SP) ← PC; PC ← (14); PS ← (16)
|
| 000004 | IOT | Input/output trap operation: -(SP) ← PS; -(SP) ← PC; PC ← (20); PS ← (22)
|
| 000006 | RTT | Return from trap sequence: PC ← (SP)+; PS ← (SP)+
|
Trap and Exception Vector Address Assignments
| Vector Address | Trigger Condition |
|---|---|
| 000000 | Reserved for future use |
| 000004 | Illegal instruction, bus error, or stack boundary violation |
| 000010 | Reserved instruction encountered |
| 000014 | Breakpoint instruction or trace trap activated |
| 000020 | IOT instruction executed |
| 000024 | Power failure detected |
| 000030 | EMT instruction invoked |
| 000034 | TRAP instruction executed |
| 000114 | Parity error condition detected |
| 000244 | Floating point exception occurred |
| 000250 | Memory management fault triggered |
Miscellaneous Instructions
| 15 | style="width:15px;" |
| Opcode | Mnemonic | Description |
|---|---|---|
| 000000 | HALT | Stop processor before executing the next instruction |
| 000001 | WAIT | Suspend execution until an interrupt handler resumes operation |
| 000005 | RESET | Drive INIT signal on UNIBUS for 10 milliseconds; reset hardware to initial power-on state |
| 000240 | NOP | Perform no operation; processor continues without action |
Condition-Code Operations
| 15 | 6 | 5 | style= " width : 1 5 px " 4 | style= " width : 1 5 px "3 | style= " width : 1 5 px "2 | style= " width : 1 5 px "1 | style= " width : 1 5 px "0 | ||||||||
Opcode |
style= "background-color:#CCC; " | 1 |
style= "background-color:#99F; " | S |
style= "background-color:#9F9; " | N |
style= "background-color:#9F9; " | Z |
style= "background-color:#9F9; " | V |
style= "background-color:#9F9; "|C | |||||||||
| Opcode | S | Mnemonic | Description |
|---|---|---|---|
| 0002 | 0 | Ccc | Clear specified condition codes N, Z, V, C bits accordingly |
| 0002 | 1 | Scc | Set condition codes based on N, Z, V, C bits as indicated |
The processor status word (PSW) contains four essential condition flags used in decision logic:
- N — Negative result indicator
- Z — Zero or equality flag
- V — Overflow indicator
- C — Carry flag
These microcoded instructions facilitate setting or clearing individual or all condition flags simultaneously. The assembler recognizes the SCC and CCC mnemonics to either set or clear all four flags in one operation. Opcodes that do not modify any bits effectively act as no-operations; notably, the NOP instruction corresponds to opcode 000240.
Variations in instruction implementation
During the PDP-11's development, slight discrepancies emerged in certain instructions and addressing modes; however, these differences did not affect the performance of standard business software.
Extended Instruction Set (EIS)
The EIS, present on the 11/35/40 and 11/03 models and included as standard on subsequent processors, improves arithmetic functions by providing:
- MUL and DIV instructions for integer multiplication and division utilizing register pairs
- ASH and ASHC for performing arithmetic shifts on either single registers or register pairs—shifting left for positive values and right for negative ones
Floating Instruction Set (FIS)
Designed for the PDP-11/35/40 and 11/03, the FIS expands floating-point capabilities. It operates on a register-based stack using single-precision floating-point numbers. Instructions determine operations through high-order bits, with a three-bit field selecting the floating-point stack pointer register. Each floating-point number occupies two consecutive words; instructions take two such numbers as input and yield one result. After execution, the stack pointer advances by four.
| 15 | 3 | 2 | 0 | ||||||||||||
| Opcode | Reg | ||||||||||||||
| Opcode | Mnemonic | Description |
|---|---|---|
| 07500 | FADD | Floating addition: 4(Rn) ← 4(Rn) + (Rn), Rn ← Rn + 4
|
| 07501 | FSUB | Floating subtraction: 4(Rn) ← 4(Rn) - (Rn), Rn ← Rn + 4
|
| 07502 | FMUL | Floating multiplication: 4(Rn) ← 4(Rn) × (Rn), Rn ← Rn + 4
|
| 07503 | FDIV | Floating division: 4(Rn) ← 4(Rn) ÷ (Rn), Rn ← Rn + 4
|
Floating-Point Processor (FPP)
The optional Floating-Point Processor, compatible with the 11/45 and most later models, supported comprehensive floating-point operations on both single- and double-precision data types. Precision selection was controlled via the Floating Point Status Register. Its single-precision format anticipated the IEEE 754 standard, featuring a sign bit, an 8-bit exponent, and a 23-bit mantissa with an implicit leading bit.
Commercial Instruction Set (CIS)
The Commercial Instruction Set (CIS or CIS11) augmented the PDP-11 architecture by introducing string manipulation and binary-coded decimal (BCD) instructions critical for business-oriented languages such as COBOL and DIBOL. This enhancement was implemented through optional microcode on models like the 11/23/24 and as an add-on module for the 11/44 and one variant of the 11/74, broadening the system’s commercial application scope.
Strings are represented using two 16-bit integers—one ("n") indicating string length (up to 64 kB), and another ("A") serving as a pointer to character data—stored either in registers or memory locations. Principal string operations include MOVEC/MOVECI for copying with optional padding or truncation using a fill character; MOVRC/MOVRCI for reverse copying; and MOVTC/MOVTCI for character translation via a 256-byte lookup table, facilitating conversions like EBCDIC to ASCII.
Instructions for string comparison and searching encompass CMPC (compare), LOCC (locate first matching character), SKPC (locate first non-matching character), SCANC, and SPANC (mask-based search operations). Character sets are defined through masks that select subsets of characters, enabling complex searches such as detecting line breaks or filtering by letter case.
CIS also supports BCD data types with instructions applicable to both packed and unpacked formats stored similarly to strings. Packed BCD can hold up to 32 digits within 16 bytes. Arithmetic operations include ADDP/ADDN, SUBP/SUBN, ASHP/ASHN (arithmetic shifting), CMPP/CMPN (comparison), with MULP and DIVP provided exclusively for packed BCD data. Conversion instructions enable transformations between packed/unpacked BCD and binary representations.
Additionally, CIS provides instructions that load two or three string descriptors—each consisting of two words—directly into internal registers. This feature optimizes string processing by eliminating multiple move instructions.
Processor Status Word (PSW) Access
The PSW resides at the memory location 177 776 and can be manipulated similarly to standard data. Most PDP-11 variants include specific instructions facilitating more direct interaction with this register:
- SPL (set priority level)
- MTPS (move to Processor Status)
- MFPS (move from Processor Status)
Accessing Additional Memory Spaces
On PDP-11 systems featuring multiple instruction and data spaces, specialized non-orthogonal Move instructions are employed to access these areas. Operating system routines that manage run-time service calls utilize these instructions for data exchange:
- MTPD (move to previous data space)
- MTPI (move to previous instruction space)
- MFPD (move from previous data space)
- MFPI (move from previous instruction space)
Sample Code
Presented below is a PDP-11 assembly routine named TOUPPER which transforms a null-terminated ASCIIZ string into uppercase characters.
<syntaxhighlight lang="nasm">
- TOUPPER
- Converts a null-terminated ASCII string to uppercase.
- Stack parameters on entry
- [SP+2] = Pointer to string
- [SP+0] = Return address
TOUPPER:
MOV R0,-(SP) ; Preserve registers
MOV R1,-(SP) MOV 6(SP),R0 ; Load string pointer
LOOP: MOVB (R0)+,R1 ; Retrieve character BEQ DONE ; Exit if zero terminator CMPB R1, #’z’ ; Check if beyond 'z' BGT LOOP CMPB R1, #’a’ ; Check if before 'a' BLT LOOP BICB #40,-(R0) ; Convert lowercase to uppercase BR LOOP
DONE: MOV (SP)+,R1 ; Restore registers MOV (SP)+,R0 RTS PC ; Return from subroutine </syntaxhighlight>
An alternative implementation demonstrates the use of PDP-11 addressing modes without relying on general-purpose registers:
<syntaxhighlight lang="nasm">
- TOUPPER2
- Converts a null-terminated ASCII string to uppercase.
- Stack parameters on entry
- [SP+2] = Pointer to string
- [SP+0] = Return address
TOUPPER2:
TSTB @2(SP) ; Test character at address on stack
BEQ DONE ; Exit if zero terminator CMPB @2(SP), #’z’ BGT NEXTC CMPB @2(SP), #’a’ BLT NEXTC BICB #40,@2(SP) ; Convert to uppercase NEXTC: INC 2(SP) ; Advance to next character BR TOUPPER2
DONE: RTS PC ; Return from subroutine </syntaxhighlight>
Performance
Processor speeds for PDP-11 models vary depending on the specific variant, memory setup, opcode executed, and addressing modes used. Instruction timing encompasses fetch/execute cycles as well as source and destination operand access durations, which depend on the addressing method. For instance, on the PDP-11/70 introduced around 1975, an ADD instruction involving memory operands required approximately 2.55 microseconds—comprising 1.35 microseconds for fetch/execute and about 0.6 microseconds each for accessing source and destination operands. Accesses outside the cache incur an additional delay of roughly 1.02 microseconds. When performing register-to-register ADD operations from cache memory, execution time reduces to approximately 0.3 microseconds. Floating-point instructions exhibit longer and more intricate timing due to concurrent operation between the CPU and floating-point unit; single-precision floating-point addition ranges from around 2.4 up to 5.5 microseconds plus the time needed for operand retrieval.
Interrupts
The PDP-11 manages interrupt priorities using a scale from 0 to 7, encoded within the Processor Status Word (PSW). Advanced models incorporate multiple operating modes, including Kernel (privileged), User, and occasionally Supervisor modes.
Interrupt requests from bus devices are signaled through lines BR4 to BR7, where a higher number corresponds to greater urgency. The processor only acknowledges interrupts that surpass its current priority level; requests that do not meet this threshold are postponed but remain pending.
Interrupts are granted via a daisy-chain bus-grant mechanism (BG4–BG7). Devices positioned closer to the CPU hold precedence in this chain; when a device accepts the grant, it stops further propagation along the bus. To ensure uninterrupted signal flow, vacant slots employ "grant continuity cards."
Upon receiving the grant, the device places the address of its two-word interrupt vector onto the bus. This vector contains both the address of the interrupt service routine and a new PSW. The processor saves its present PC and PSW, transitions into Kernel mode, loads new values from the vector, and jumps to execute the service routine. Typically, the updated PSW elevates the priority level to permit higher-priority interrupts during servicing while deferring those of equal or lower priority. The interrupt handler concludes with an RTI instruction that restores the PC and PSW.
If no device responds to a bus grant, the processor experiences a timeout and initiates a trap signaling a hardware fault.
MACRO-11 assembly language
MACRO-11 serves as the assembly language for the PDP-11, succeeding PAL-11, an earlier assembler for the PDP-11 that lacked macro functionality. MACRO-11 is compatible with all DEC PDP-11 operating systems. The PDP-11 Unix variants utilize an assembler known as "as," which shares structural similarities with MACRO-11 but differs in syntax and offers fewer features.
See also
- WD16, an extension of the PDP-11 instruction set architecture
Further reading
- Richard H. Eckhouse Jr. and L. Robert Morris, Microcomputer Systems Organization, Programming and Applications (PDP-11), Prentice-Hall, 1979.
- Michael Singer, PDP-11: Assembler Language Programming and Machine Organization, John Wiley & Sons, 1980.
- PDP-11 Processor Handbook - PDP11/05/10/35/40, Digital Equipment Corporation, 1973.
- PDP-11 Processor Handbook - PDP11/04/34a/44/60/70, Digital Equipment Corporation, 1979.