The PDP-11 processor has a small but powerful set of instructions. There are instructions to add and subtract numbers, move values between registers and memory locations, compare values, branch to other instructions if certain conditions are met, call subroutines, pause the processor until an interrupt occurs, or even halt the processor altogether.
When a PDP-11 processor is ready to execute an instruction, it looks at the value of the program counter register (R7, aka PC). It then reads the instruction word from the address indicated by the program counter and increments PC by two, so it points to the next word.
The instruction is a word. The format of the word determines which operation to perform. If the value is 005303, the processor will decrement the value of R3. If the value is 005203, the processor will increment the value of R3. If the value is 005204, the processor will increment the value of R4. If the value is 005214, the processor will increment the value of the memory at the location stored in R4. There is a pattern to the instruction values. Much of the processors' circuitry is dedicated to decoding the instruction format and determining what to do.
Since it would be difficult for a programmer to memorize all of these patterns, the instructions are given a human-readable format, called "mnemonics" with optional operands. When taken together, they form a primitive language, called "assembly language". Programs called "assemblers" can take assembly language programs and convert them to the instruction values as seen above.
Examples of these mnemonics:
DEC R3
INC R3
INC R4
INC (R4)
The PDP-11 instructions can be categorized into a few sets:
- Instructions that take two operands, like addition.
- Instructions that take one operand, like increment.
- Instructions that change the PC based on the processor status register.
- Instructions that change the process status register condition bits.
- Instructions that call and return from subroutines.
- Instructions that handle interrupts.
- Instructions that halt or reset the computer.
Instructions that take operands need to tell the processor what those operands are. The operands are either register values, or memory locations based on those register values. For the general registers R0 through R6, there are eight ways to find the operand based on a register. These are called "addresing modes". Each of them has a number, which is embedded in the instruction along with the register number.
-
Mode 0: Register: The operand is the value of the register. In assembly language, this is written as Rn:
INC R3
will increment the value of R3.Instruction Before After INC R3
R3: 001000
R3: 001001
-
Mode 1: Register Deferred: The operand is the value of the memory location stored in the register. This is written as (Rn) or @Rn:
INC (R3)
will increment the memory value pointed to by R3.Instruction Before After INC (R3)
R3: 002000
002000: 012345
R3: 002000
002000: 012346
-
Mode 2: Auto Increment: Like register deferred mode, the operand is the value of the memroy location stored in the register. Once the operand is read, the value of the register is incremented by one if this is a byte instruction, or two if the register is a word instruction. This is written as "(Rn)+":
INC (R3)+
will increment the memory value of the word pointed to by R3, then adds two to R3, which points R3 to the next word.INCB (R3)+
will increment the memory value of the byte pointed to by R3, then adds one to R3, pointing it to the next byte. This useful when operating within a loop.Instruction Before After INC (R3)+
R3: 002000
002000: 012345
R3: 002002
002000: 012346
INCB (R3)+
R3: 002000
002000: 125
R3: 002001
002000: 126
-
Mode 3: Auto Increment Deferred: The operand is the value at the memory address in the location given in the register. The register is then incremented by two. Written as "@(Rn)+". The instruction
INC @(R3)+
will increment the value the memory address in the location pointed to by R3, and adds two to R3. This is useful while iterating over a list of pointers.Instruction Before After INC @(R3)+
R3: 002000
002000: 004444
004444: 000000
R3: 002002
002000: 004444
004444: 000001
-
Mode 4: Auto Decrement: Like auto increment mode, except the value of the register is decremented before it is used to look up a value in memory. Written as "-(Rn)". The instruction
INC -(R3)
will subtract two from R3, then increments the value at the location given by R3.Instruction Before After INC -(R3)
R3: 002000
001776: 012345
R3: 001776
001776: 012344
INCB -(R3)
R3: 002000
001777: 125
R3: 001777
001777: 124
-
Mode 5: Auto Decrement Deferred: The value of the register is decremented by two. The operand is the value at the memory address in the location given in the register. Written as "@-(Rn)". The instruction
INC @-(R3)
will subtract two from R3, then increment the value at the memory location that appears in the memory location pointed to by R3.Instruction Before After INC @-(R3)
R3: 002000
001776: 004444
004444: 000000
R3: 001776
001776: 004444
004444: 000001
-
Mode 6: Indexed: The operand is at the location given by the register plus the index value in the word after the instruction. Written as "X(Rn)". The instruction
INC 6(R3)
will increment the value at the memory location given by 6+R3. This is useful when dealing with structucred data.Instruction Before After INC 6(R3)
R3: 002000
002006: 000000
R3: 002000
002006: 000001
-
Mode 7: Indexed Deferred: The operand is the value in the memory address in the location given by the register plus the index word, which appears after the instruction. Written as "@X(Rn)". The instruction
INC @6(R3)
will increment the value at the memory address that appears at memory location 6+R3.Instruction Before After INC @6(R3)
R3: 002000
002006: 004444
004444: 000000
R3: 002000
002006: 004444
004444: 000001
If an instruction uses the program counter (R7), some of the modes work a little differently.
-
Mode 2: Immediate: The operand is the value in the word that follows the instruction word. The PC is then incremented by two to point to the next word. This is written as #nnnnnn:
ADD #42,R2
adds 42 (octal, of course) to R2. Typically only useful as a source operandInstruction Before After ADD #42,R2
R2: 000200
R2: 000242
-
Mode 3: Absolute: The operand is the value in the memory address pointed to by the word that follows the instruction. The PC is then incremented by two to point to the next word. This is written as @#nnnnnn:
ADD @#2000,R2
adds the value of memory location 2000 to R2.Instruction Before After ADD @#2000,R2
R2: 00100
002000: 001234
R2: 001334
002000: 001234
ADD @#2000,@#3000
002000: 001234
003000: 000100
002000: 001234
003000: 001334
-
Mode 6: Relative: The operand is the value at the address of the current instruction plus the word after the instruction. Some assemblers use this mode when referring to a symbolic label in the code, like
INC CTR
.Instruction Before After INC CTR
CTR: 001000
CTR: 001001
-
Mode 7: Relative Deferred: The operand is the value at the address that appears at the current instruction plus the word after the instruction. This appears as
INC @CTR
.Instruction Before After INC @CTR
CTR: 001000
001000: 012345
CTR: 001000
001000: 012346
The mode numbers and the registers they refer to are encoded into instruction words. For example, instructions that take two operands are encoded as
+-+---+---+---+---+---+
| op | sm| sr| dm| dr|
+-+---+---+---+---+---+
where "op" is the operation (1=move, 2=compare, etc.), "sm" is source addressing
mode, "sr" is source register, "dm" is destination addressing mode, and "dr" is
destination register. For example, the instruction MOV (R4)+,R5
is encoded as
012405
The operation is 01, the source is R4, autoincrement, the destination is R5 register.
The instruction MOV #123456,2(R3)
is encoded as three words
012763
123456
000002
The first word says that this is MOV (op=01), the source is an immediate value (mode 2, register 7), and the destination is using indexed addressing (mode 6, register 3). The second word is the immediate value for the source operand, the third word is the index value for the destination operand.
The double operand instructions are
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
move | MOV | 01 | Sets the destination operand to the value of the source operand. |
compare | CMP | 02 | Subtracts the source from the destination, discards the result. |
test bits | BIT | 03 | Performs a logical AND of the source and destination, discards the result. |
clear bits | BIC | 04 | Clears the desitnation bits that are set in the source. |
set bits | BIS | 05 | Sets the bits in the destination that are set in the source. |
add | ADD | 06 | Adds the source to the destination. |
subtract | SUB | 16 | Subtracts the source from the destination. |
There are also instructions that operate on byets:
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
move byte | MOVB | 11 | Sets the destination byte to the value of the source operand. |
compare byte | CMPB | 12 | Subtracts the source byte from the destination byte, discards the result. |
test bits in byte | BITB | 13 | Perform a logical AND of the source and destination bytes, discards the result. |
clear bits in byte | BICB | 14 | Clears the destination bits that are set in the source byte. |
set bits in byte | BISB | 15 | Sets the destination bits that are set in the source byte. |
Each of these instructions sets the processor status word bits:
Z is set if the result is zero. N is set if the most significant bit is zero. V is cleared for all instructions other than ADD, SUB, and CMP. For these instructions this flag is set if the operands had opposite signs and the sign of the result is the same as the destination, indicating an arithmetic overflow. If this did not happen, V is cleared. C is untouched for all instructions other than ADD, SUB, and CMP. For these instructions, this bit is set if there was a carry from the most significant bit.
The single operand instructions are encoded as
+-+---+---+---+---+---+
| op | dm| dr|
+-+---+---+---+---+---+
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
clear | CLR | 0050 | Clears the destination to zero. |
compliment | COM | 0051 | Flips the bits of the destination. |
increment | INC | 0052 | Increments the destination by one. |
decrement | DEC | 0053 | Decrements the destination by one. |
negate | NEG | 0054 | Replace the destination with its twos' compliment value. |
add carry | ADC | 0055 | Adds the value of the carry bit to the destination. |
subtract carry | SBC | 0056 | Subtracts the value of the carry bit from the destination. |
test | TST | 0057 | Compare destination with zero. |
rotate right | ROR | 0060 | Rotate destination bits to the right through the carry bit. |
rotate left | ROL | 0061 | Rotate destination bits left through the carry bit. |
arithmetic shift right | ASR | 0062 | Shift bits the the right, without modifying the high bit. |
arithmetic shift left | ASL | 0063 | Shift bits the the left, setting low bit to zero. |
jump | JMP | 0001 | Set the program counter to the destination. Destination cannot use register mode. |
swap bytes in word | SWAB | 0003 | Exchange the high and low bytes in a word. |
And their corresponding byte-oriented instructions
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
clear byte | CLRB | 1050 | Clears the destination to zero. |
compliment byte | COMB | 1051 | Flips the bits of the destination. |
increment byte | INCB | 1052 | Increments the destination by one. |
decrement byte | DECB | 1053 | Decrements the destination by one. |
negate byte | NEGB | 1054 | Replace the destination with its twos' compliment value. |
add carry to byte | ADCB | 1055 | Adds the value of the carry bit to the destination. |
subtract carry from byte | SBCB | 1056 | Subtracts the value of the carry bit from the destination. |
test byte | TSTB | 1057 | Compare destination with zero. |
rotate right byte | RORB | 1060 | Rotate destination bits to the right through the carry bit. |
rotate left byte | ROLB | 1061 | Rotate destination bits left through the carry bit. |
arithmetic shift right byte | ASRB | 1062 | Shift bits the the right, without modifying the high bit. |
arithmetic shift left byte | ASLB | 1063 | Shift bits the the left, setting low bit to zero. |
Branch operations change the program counter if certain bits of the processor status word are set or clear. These operations do not use registers, but encode the number of bytes to add (or subtract) if the conditions are met directly in the instruction. These instructions have the form
+-+---+---+---+---+---+
| op >< offset|
+-+---+---+---+---+---+
Since there are eight bits for offset, and is treated as a singed value, the lowest offset is 200 (-128 decimal), the highest is 177 (127 decimal). If a program needs to branch further away, branch should be used with a jump instruction. Some assemblers provide a pesudo-mnemonic that handles this automaticaly.
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
branch unconditionally | BR | 0004 | Branch regardless of the flags. |
branch if not equal | BNE | 0010 | Branch if Z=0 |
branch if equal | BEQ | 0014 | Branch if Z=1 |
branch if greater or equal | BGE | 0020 | Branch if N and V are different. |
branch if less than | BLT | 0024 | Branch if one of N or V is set. |
branch if greater than | BGT | 0030 | Branch if Z=1 or if N and V are different. |
branch if less than or equal | BLE | 0034 | Branch if Z=1 or if one of N or V is set. |
branch if plus | BPL | 1000 | Branch if N=0 |
branch if minus | BMI | 1004 | Branch if N=1 |
branch if higher | BHI | 1010 | Branch if both C or Z are 0. |
branch if lower or same | BLOS | 1014 | Branch if C or Z is 1. |
branch if overflow clear | BVC | 1020 | Branch if V=0 |
branch if overflow set | BVS | 1024 | Branch if V=1 |
branch if carry clear | BCC | 1030 | Branch if C=0. Also "branch if higher or same" (BHIS) |
branch if carry set | BCS | 1034 | Branch if C=1. Also "branch if lower" (BLO) |
Condition Code instructions can directly modify the processor status bits. Most assemblers have mnemonics that set or clear one bit at a time, but a clever programmer can set or clear multiple status bits with a single instruction. These instructions have the format
+-+---+---+---+---+---+
|0| 0| 0| 2|1SN|ZVC|
+-+---+---+---+---+---+
Operation | Mnemonic | Instruction |
---|---|---|
clear carry | CLC | 000241 |
clear overflow | CLV | 000242 |
clear zero | CLZ | 000244 |
clear negative | CLN | 000250 |
set carry | SEC | 000261 |
set overflow | SEV | 000262 |
set zero | SEZ | 000264 |
set negative | SEN | 000270 |
The next two instructions which implement subroutine calls have special formats.
The Jump to Subroutine instruction has the format
+-+---+---+---+---+---+
|0| 0| 4|reg| dm| dr|
+-+---+---+---+---+---+
where reg is the "link register", and "dm" and "dr" are destination mode and registear.
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
jump to subroutine | JSR | 004 | Push the link register to the stack, and put the PC into the register. Set the PC to the destination. Destination cannot be used with register mode. |
The Return from Subroutine instruction has the format
+-+---+---+---+---+---+
|0| 0| 0| 2| 0|reg|
+-+---+---+---+---+---+
Operation | Mnemonic | Opcode | Description |
---|---|---|---|
return from subroutine | RTS | 00020 | Move the register to PC, and pop the register from the stack. |
The remaining instructions are for low level machine operations and program traps. These are typically used by operating systems, and are rarely used by most programs. They are included here for completeness.
Operation | Mnemonic | Instruction | Description |
---|---|---|---|
halt | HALT | 000000 | Halts the computer, requiring an operator to physically press the "continue" button |
wait for interrupt | WAIT | 000001 | Pauses the computer until an interrupt is raised. |
return from interrupt | RTI | 000002 | Return control from an interrupt service routine. |
I/O trap | IOT | 000004 | Calls the interrupt routine at vector address 14. Typically used for debugging. |
Reset bus | RESET | 000005 | Assert a bus reset. |
emulator trap | EMT | 104xxx | Calls the interrupt routine with a vector address of 30. "xxx" in the range of 000-377. Often used to implement calls to the operating system. |
software trap | TRAP | 104xxx | Calls the interrupt routing with a vector address of 34. "xxx" in the range of 400-777. |
These are the instructions available to the PDP-11/20 KA11 processor. DEC also sold additional options that include multiply and divide instructions, as well as instrutions to support floating point arithmetic. Additional instructions were also added to later PDP-11 machines as the architecture expanded to support multitasking with task isolation.
A simple program to add two to three would use the instructions
012700 (MOV immediate in next word to register R0)
000002
062700 (ADD immediate in next word to register R0)
000003
010037 (MOV register R0 to the absolute address in the next word)
002000
000000 (HALT the processor)
Using the programmer's console, the programmer can load address 1000, then deposit these five instructions into the next five words of memory. The programmer could then use the console to verify these words are in address 1000 through 1014. They can then set the switches back to 1000, press the "load address" switch, and finally press the start button. Upon setting the switches to 2000, pressing the "load address" then "exam" switches, the programmer should see the result 5 stored at address 2000.