The Digital Equipment Corporation PDP-8

Memory Reference Instructions

Part of the PDP-8 Programmer's Reference Manual
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science


Instruction Format

            00 01 02 03 04 05 06 07 08 09 10 11
           |  |  |  |  |  |  |  |  |  |  |  |  |
           |        | I| Z|       7 bit        |
           |  3 bit |     |    Word in Page    |
           | Opcode | Mode                     |
           |        |         Address          |


000 - AND


The contents of memory location M are logically anded with AC, bit by bit. There is no effect on the link bit. All other logical operations must be accomplished with macros.

001 - TAD


The contents of memory location M are added to AC. A carry out of the high bit of AC will complement the link bit. Most other arithmetic operations must be accomplished with macros.

010 - ISZ


The contents of memory location M are incremented and placed back in memory. If the result stored in memory is zero, the program counter is incremented; as a result that the next instruction will be skipped if the result is zero. AC and LINK are not modified.

ISZ is frequently used to increment memory addresses; unless the address could wrap around from 7777 to 0000, ISZ is used as if it will never skip. If a wraparound is possible, it must be followed by a no-op.

ISZ allows the construction of a number of fast macros for block operations.

011 - DCA


The contents of the accumulator are stored in the memory location M; the accumulator is then cleared. There is no effect on the link bit. The corresponding load operation must be accomplished by a macro

100 - JMS


The contents of PC (a pointer to the next instruction) is stored in memory location P as a return address, and then control is transfered to the location following P. AC and LINK remain unchanged. There is no return instruction; this is done using an indirect jump through P.

101 - JMP


Control is transferred to memory location P. AC and LINK remain unchanged.

Addressing Modes

Z - The Page Select Bit


When the Z bit of the instruction is zero, page zero addressing mode is used. This allows addressing of memory locations 0000 through 0177 (octal) of the current memory from an instruction located anywhere in theat field. The Z qualifier may be used to indicate that page zero mode is desired, but most PDP-8 assemblers will automatically generate page zero mode if the addressed location is in page zero.

When the Z bit of the instruction is one, current page addressing mode is used. This allows addressing of memory locations in the current page, as determined by the 5 most significant bits of the program counter (more accurately, the 5 most significant bits of the address of the location from which the instruction was fetched). All PDP-8 assemblers will generate current page mode when the addressed location is in the current page.

Direct addressing of locations not on the current page is impossible, but some PDP-8 assemblers will automatically generate indirect references to off-page locations, storing the indirect word at the end of the current page. This usage is considered unsafe because indirection may change the memory field being referenced!

I - The Indirect Bit


When the I bit of the instruction is zero, direct addressing is used. This allows any word in either page zero or the current page to be referenced as an operand.

When the I bit of the instruction is one, indirect addressing is used. In this mode, the word at the addressed location in page zero or the current page is used as a pointer to the intended operand. This requires one additional memory cycle for the instruction.

All PDP-8 assemblers require the use of the I qualifier to indicate indirect mode. Some PDP-8 assemblers will automatically generate indirect references for those instructions that directly reference off-page locations.

Indirect addressing using locations 0010 through 0017 (octal) has the side effect of incrementing these locations prior to use. This is called autoindexed addressing .

Indirect addressing may be used to reference operands in any memory field, depending on how the DF (data_field) register is set. By default, this is usually the current field, the same field as that from which the instruction was fetched.

Autoindex Addressing

If indirect addressing is done through locations 0010 and 0017 (octal) of any memory field, the indirect word will be incremented prior to use. Other than this increment, auto-indexed mode is the same as indirect mode. Autoindex addressing is particularly useful for operations on blocks of consecutive words.

Immediate Addressing

The PDP-8 does not support any immediate addressing mode, however, there are microcoded instructions that can be used to load a number of useful constants in the accumulator in a single machine cycle, and most PDP-8 assemblers support a notation for immediate constants.

	TAD	(7)	/ add the constant 7
	JMS I	[PROC]	/ call PROC
	TAD I	(LOC)	/ add the contents of LOC

If an operand is enclosed in parentheses or square brackets, most PDP-8 assemblers will treat the operand as a value intended to be used as an immediate constant. To do this, the indicated value is stored in a memory location, and the instruction is then assembled with the address of that location as an operand.

If parentheses are used, the operand is stored at the end of the current page, while if square brackets are used, the operand is stored at the end of page zero. All common PDP-8 assemblers will attempt to optimize constant storage, checking to see if a constant in question has already been stored at the end of the page in question and re-using that constant if so.

The usage JMS I [PROC] is a standard way to call an off-page procedure. This allocates a pointer to PROC at the end of page zero; this pointer will be used by all other references to PROC that are coded the same way.

The usage TAD I (LOC) is a standard way to reference a variable LOC that is on a different page and that is local in the sense that it only concerns a small number of routine. In this case, a pointer to LOC will be allocated at the end of the current page and shared only by other references to LOC made from the same page.


The PDP-8 instruction set is so small that many operations that are usually single instructions on a larger machine must be performed by instruction sequences on the PDP-8. While these are referred to as macros here, the memory resources of the PDP-8 are limited enough that these are usually not coded as given, but rather, carefully folded into other computations.

Loading the Accumulator

There is no load accumulator instruction on the PDP-8. As a result, if the contents of location M are to be loaded into the accumulator, the following instruction sequence should be used:
In the event that the accumulator is already known to be zero, for example, because the previous instruction was a DCA operation, the above can be abbreviated to a simple TAD instruction. Other sequences are also effective, for example, it is possible to and M with -1 to get the same effect.

In general, the PDP-8 does not support immediate operands, but there are single-cycle microcoded instructions sequences that load commonly used constants in memory. These are conventionally defined using the notation NLXXXX in PAL, where XXXX is the octal constant to be loaded. These are usually defined, as needed, at the start of each PAL program:

NL0000=	CLA		/    0
NL0001= CLA IAC		/    1
NL0002= CLA CLL CML RTL /    2
NL2000= CLA CLL CML RTR / 1024
NL3777= CLA CMA CLL RAR / 2047
NL4000= CLA CLL CML RAR / 2048

NL7777= CLA CMA		/   -1 or 4095
NL7776= CLA CMA CLL RAL /   -2 or 4094
NL7775= CLA CMA CLL RTL /   -3 or 4093
Given these definitions, the instruction NL0001, for example, will load 1 in the accumulator. Note that the instruction NL0000 is rarely defined or used (it means no more or less than CLA), and note that these instructions have ill defined effects on the LINK bit. Some set it, some reset it, and others leave it as it was.

Other Logical Operations

The only built in logic operations on the PDP-8 are the not and bitwise and operations. All others must be accomplished using instruction sequences.


The most obvious way to or the accumulator with a value M from memory is to use De Morgan's law, along with TMP, a temporary location.
	CMA		/ complement accumulator
	DCA	TMP	/   TMP = not(AC)
	TAD	M	/ get value to or with accumulator
	CMA		/ complement it
	AND	TMP	/   AC = not(M) and not(TMP)
	CMA		/ complement result

A clever alternative is to clear all bits from one operand that are set in the other before adding the operands. If both operands are initially in memory, this alternative is faster and no temporary location is needed.

	DCA	TMP	/ copy the operand
	AND	TMP	/ AC = bits set in both TMP and M
	AND	TMP	/ AC = TMP - (bits set in both)
	TAD	M	/ AC = TMP or M

Exclusive Or

The xor operation is sufficiently complex that a subroutine is usually called for. This operation can be performed using the following identity from boolean algebra:
a xor b = (a and not b) or (b and not a)
But leads to inefficient code. A better solution rests on the fact that binary addition is based on exclusive or, if only the carry bit can be defeated, as follows:
a xor b = (a + b) - 2*(a and b)
The second term computes the bits that will cause carrys; these carry bits are then subtracted from the sum. In PDP-8 assembly language, this can be done as follows, using TMP, a temporary location.

Other Arithmetic Operations


To subtract a value M from the accumulator, the value must be two's complemented and then added to the accumulator. This requires TMP, a temporary location.
	DCA	TMP	/ set aside accumulator
	TAD	M	/ get value to subtract from it
	CMA IAC		/ 2's complement it
	TAD	TMP	/ add back saved value
It is significantly faster to do reverse subtraction, subtracting the accumulator from M, the contents of a memory location, leaving the result in the accumulator.
	CMA IAC		/ 2's complement accumulator
	TAD	M	/ add operand from memory


The following algorithm iteratively counts the number of one bits in a word W and returns the result in the accumulator:
The above bit of code will, in the worst case, require as many as 12 iterations of the loop body, at a cost of 6 memory cycles per iteration. Loop unrolling can reduce this, as illustrated below:
LOOP,	CLL RAR		/ test bit
	CLL RAR		/ test bit
	CLL RAR		/ test bit
	SZA		/ end loop if no more bits
	JMP	LOOP	/  otherwise iterate

Block Memory Operations

In the instruction sequences for block operations, the bulk of the code is usually concerned with setting up the auto-increment locations used to index through the block or blocks being manipulated, and to setup the count of words per block. In all of the following instruction sequences, the labels X1 and X2 are assumed to reference autoincrement locations, and TMP is any directly addressable temporary, used as a loop counter. The comments are essentially transliterations to C.

Block Zero

The following instruction sequence zeros a block of memory, starting from LOC and occupying CNT words.
	DCA	X1	/ X1 = LOC-1

LOOP,			/ do {
	DCA I	X1	/   M[++X1] = 0
	ISZ	TMP	/   TMP++
	JMP	LOOP	/ } while (TMP!=0)

Block Copy

The following instruction sequence copies a block of memory from the block starting at SRC to the block starting at DST; CNT words are copied.
	DCA	X1	/ X1 = SRC-1
	DCA	X2	/ X2 = DST-1
	DCA	TMP	/ setup TMP = -CNT

LOOP,			/ do {
	DCA I	X2	/   M[++X2] = M[++X1]
	ISZ	TMP	/   TMP++
	JMP	LOOP	/ } while (TMP!=0)