DEC PDP-8 Interrupts

Mark Smotherman. Last updated October 2003.

Introduction

The PDP-8 was the first mass-produced minicomputer. It was a 12-bit, word-addressed, accumulator-based design, first shipped in 1965. It was influenced by the CDC 160, the MIT Lincoln Labs LINC, and the DEC PDP-5.

Instructions are one 12-bit word each.

        +-----+-+-+-------------+
        | opc |i|p|    offset   |
        +-----+-+-+-------------+
         0 1 2 3 4 5 6 7 8 9 a b

           opc     3-bit opcode
           i       1-bit direct/indirect addressing mode
           p       1-bit global/current page for high address bits
           offset  7-bit offset

           effective address = p ? ( top 5 bits of last pc # offset )
                                 : ( 00000 # offset );
A notable feature of the PDP-8 was the lack of a load instruction. Instead, you would first clear the accumulator (cla) and then add the contents of a memory loaction to the accumulator (tad). The function of a store was done by the deposit and clear accumulator (dca) instruction. The PDP-8 did provide a fast loop-closing instruction, increment and skip if zero (isz), that did not use the accumulator. The isz instruction was also used as a general way to increment memory locations apart from its function in loops.

Interrupts

A single interrupt enable bit controlled whether or not interrupts would be accepted. Upon an interrupt,

  1. the enable flag would be reset to 0 (disabled),
  2. the updated PC would be saved into memory at address 0, and
  3. the PC would be reset to address 1.

Since the PC was saved to a fixed memory location, nested interrupts are not allowed until the interrupt handler saves the interrupted-PC, accumulator, and link bit into a memory stack. A instruction exists to reenable interrupts.

Since there is only one entry point, the interrupt handler has to poll the I/O devices and clock to determine which one caused the interrupt. This was done by using a set of device-specific skips and jumps to the corresponding device handlers. The overall structure of skips and jumps was called a skip chain. Device-specific skips were provided for the ADC, clock, disk, keyboard, and teletype. Device priority is thus equivalent to the position of the corresponding device-specific skip in the skip chain.

After handling the interrupt, the device-specific handler would need to restore the saved accumulator and link bit and re-enable interrupts before returning to the interrupted program. This was typically accomplished by jumping to a common epilog. The effect of the instruction to re-enable interrupts was delayed by one instruction so that it could be placed as the next-to-last instruction in the exit epilog and thus allow the return jump to execute before another interrupt was allowed.

/
/ skeleton of interrupt driven program with clock and keyboard interrupts
/

*0
        0               / reserve word to save program counter on interrupt
        jmp i pints     / jump to interrupt handler
pints,  inthnd          / address of interrupt handler
accsav, 0               / reserve word to save accumulator
lnksav, 0               / reserve word to save link
ticks,  0               / count of clock ticks

/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/
/ main routine
/
*200
start,  cla cll         / clear acc and link
        dca ticks       / clear clock tick counter
        clkt            / start the clock
        ion             / enable interrupts

      / ... main program ...

        iof             / disable interrupts
        hlt             / stop execution

/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/
/ initial interrupt handler
/
*400
inthnd, dca accsav       / save acc and link
        rar
        dca lnksav
/
/ skip chain to determine source of interrupt
/
        clksf            / skip next inst if clock flag set
        skp              / unconditional skip
        jmp clksrv
        ksf              / skip next inst if keyboard flag set
        skp              / unconditional skip
        jmp kbdsrv

      / ... rest of chain ... 

        hlt              / unknown interrupt

/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/
/ common epilog to return from interrupt
/
xit,    cla cll
        tad lnksav       / restore registers
        ral
        tad accsav
        ion              / re-enable interrupts
        jmp i 0          / return

/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/
/ clock service routine
/
clksrv, clkcf            / clear clock flag
        isz ticks        / increment tick counter
        nop
        jmp xit

/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/
/ keyboard service routine
/
kbdsrv, krb              / read keyboard (clears keyboard flag)
        dca char         / store character in circular buffer
        tad inbuf        / base address
        tad inptr        / + index
        dca temp         / = required address
        tad char
        dca i temp       / character stored in "inbuf[inptr]"
        tad inptr        /   NOTE: no buffer overflow logic in
        iac              /   this version
        and m177         / force inptr to stay in range 0-177 octal
        dca inptr
        jmp xit
char,   0
inptr,  0
temp,   0
m177,   0177
*1000
inbuf,  0

Other resources


[History of interrupts page] [Mark's homepage] [CPSC homepage] [Clemson Univ. homepage]

mark@cs.clemson.edu