logo

PDP-8 Simulator

Ward Cunningham  
Cunningham & Cunningham, Inc.  
 

The Digital Equipment Corporation's PDP-8 minicomputer offered tabletop computing at a time when human hands still wove cores. By 1975 retired instances of DEC's most popular eight, the PDP-8e, were showing up on the surplus market. My friend Jim Wilson had one for which I wrote amateur radio software. 

I wrote this PDP-8 simulator at the same time. One could assemble a program with no more than a basic 8 and a teletype. But the arduous process involving feeding multiple paper tapes multiple times through the teletype's ten character per second reader. I opted for the remote batch environment offered by the university's CDC-6000 series mainframe. I used this simulator to run the stock PAL-8 assembler from a timesharing terminal. 

I was concerned with execution speed since I expected to run assemblies often and would be waiting for them to finish. But I was even more concerned with development speed. Time spent on the simulator wasn't going into my radio programs. I implemented only those features used by PAL-8. I wrote in a mixture of FORTRAN and 6000 assembler using a conservative style. I had only one error. I had the sense of test wrong for the SZA instruction. I tracked it down by running DEC's hardware diagnostics. (See note below.) 
 

Instructions

while run 
    ir = mem[pc] 
    pc = pc+1 
    case ir 
        ... 
 
The simulator fetches instructions and then executes them. All PDP-8 instructions occupy a single twelve-bit word. The first three bits of an instruction identify one of eight instructions. Six of the instructions operate on memory locations addressed by the remainder of the instruction word in a standard way. 
 
    OPERATION     MEMORY  
   _CODES 0-5_     PAGE  
  /___ ___ ___\___/___\___ ___ ___ ___ ___ ___ ___  
  |   |   |   |   |   |   |   |   |   |   |   |   |  
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|  
  |___|___|___|___|___|___|___|___|___|___|___|___|  
              \   /   \_________         _________/  
             INDIRECT            ADDRESS  
            ADDRESSING  

     Memory Reference Instruction Bit Assignments 

Address decoding begins with the lower seven instruction bits forming an offset within a memory page. These are either merged with bits from the program counter or zeros to address a word in the current page or first page respectively. This addressed word is then used directly as the operand or indirectly as the address of the operand. As a final twist, a few words of every page will automatically increment with each indirect reference through them. 

Note: Ben Fairbank (personal correspondence, 2001) has pointed out that autoindexing only worked on page zero. Here is the description from Introduction to Programming, Digital Equipment Corporation, 1973. Apparently neither the machine diagnostics or the PAL assembler depended on this distinction.
 

 
 
 

 
Fetch-Execute 
Progressive Rotate 
Jump Table

 INT1     (bookkeeping)  

 INT1.1   FETCH  X5,X7       GET INSTRUCTION 
          SX6    X7-6000B  
          PL     X6,INT4     IF OPR OR IOT 
          MX6    -7  
          BX3    -X6*X7      EXTRACT PAGE ADDR 
          LX7    59-7  
          PL     X7,INT2     IF PAGE ZERO  
          BX1    X6*X5 
          BX3    X3+X1       INSERT CURRENT PAGE ADDR  
 INT2     LX7    7-8 
          PL     X7,INT3     IF DIRECT REFERENCE 
          BX4    X3  
          FETCH  X4,X3 
          MX1    -3  
          BX1    X1*X4 
          SX1    X1-10B  
          NZ     X1,INT3     IF NOT AUTO-INDEX REG 
          SX3    X3+B1       PRE INDEX 
          BX3    X0*X3 
          STORE  ,X3 
 INT3     LX7    8-59  
 INT4     LX7    59-8  
          SB6    X7  
          SX5    X5+B1       BUMP PC 
          BX5    X0*X5 
          JP     B6+INT5 

 INT5     (Jump table)

 
Instruction dispatching takes us to one of eight handlers, seven here and one more in the next section. The six memory referencing instructions are handled in place. The IOT handler calls a FORTRAN subroutine that appears later.
AND 
  logical and 

TAD 
  two's comple- 
  ment add 

ISZ 
  increment and 
  skip if zero 

DCA 
  deposite and 
  clear accumu- 
  lator 

JMS 
  jump to 
  subroutine 
(store return 
  in first word) 

JMP 
  jump 

OPR 
  operate 
 (on machine 
  registers) 

IOT 
  input/output 
  transfer

 
 AND      FETCH  X3,X4 
          BX2    X2*X4 
          EQ     INT1  
   
 TAD      FETCH  X3,X4 
          MX6    -13 
          IX2    X2+X4 
          BX2    -X6*X2  
          EQ     INT1  
   
 ISZ      FETCH  X3,X4 
          SX4    X4+B1 
          BX4    X0*X4 
          STORE  ,X4 
          NZ     X4,INT1 
          SX5    X5+B1 
          BX5    X0*X5 
          EQ     INT1  
   
 DCA      BX4    X0*X2 
          STORE  X3,X4 
          BX2    -X0*X2  
          EQ     INT1  
   
 JMS      STORE  X3,X5 
          SX5    X3+B1 
          BX5    X0*X5 
          EQ     INT1  
   
 JMP      BX5    X3  
          EQ     INT1  

 IOT      LX7    8-59  
          BX4    X7  
          RJ     SAVREG  
          RJ     =XPDP8IOT 
          RJ     RESREG  
          EQ     INT1 

 
The OPR instruction encodes a variety of register operations into the remaining bits of the instruction word. Multiple operations can be microcoded into a single instruction by setting multiple of these bits. The bits are assigned meaning in groups. We begin with group one. 

                                          ROTATE 1  
                                  ROTATE  IF A 0,  
    OPERATION                    AC AND L   2  
   __ CODE 7 _     CLA     CMA    RIGHT   IF A 1  
  /___ ___ ___\___/___\___/___\___/___\___/___\___  
  |   |   |   |   |   |   |   |   |   |   |   |   |  
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|  
  |___|___|___|___|___|___|___|___|___|___|___|___|  
              \   /   \   /   \   /   \   /   \   /  
            CONTAINS   CLL     CML    ROTATE   IAC  
             A 0 TO                  AC AND L  
             SPECIFY                   LEFT  
             GROUP 1  

     Group 1 Operate Instruction Bit Assignments 
 

 
 
Skip Chain
 OPR      (Group decoding) 
   
 GP1      LX7    8-7 
          PL     X7,GP1.1  
          BX2    -X0*X2      CLA 
 GP1.1    LX7    7-6 
          PL     X7,GP1.2  
          BX2    X0*X2       CLL 
 GP1.2    LX7    6-5 
          PL     X7,GP1.3  
          BX2    X0-X2       CMA 
 GP1.3    LX7    5-4 
          PL     X7,GP1.4  
          BX2    -X0-X2      CML 
          MX6    -13 
          BX2    -X6*X2  
 GP1.4    LX7    4-0 
          PL     X7,GP1.5  
          SX2    X2+B1       IAC 
          MX6    -13 
          BX2    -X6*X2  
 GP1.5    MX6    -3  
          BX6    -X6*X7  
          SB6    X6  
          JP     GP1.6+B6  

  GP1.6    (Jump table) 
 

 
The last few bits of OPR's group one encoding are most easily decoded with another dispatch.
 
 BSW      BX6    -X0*X2  
          BX1    X0*X2 
          LX1    6 
          BX2    X0*X1 
          AX1    12  
          BX2    X2+X1 
          BX2    X2+X6 
          EQ     INT1  
   
 RAL      MX1    -13                (Duplicated for RTL,RAR,RTR) 
          LX2    1  
          BX6    X1*X2  
          BX2    -X1*X2   
          AX6    13   
          BX2    X2+X6  
          EQ     INT1  
 
Group two OPR encoding assigns mostly different meanings to the remaining instruction bits. 

                                 REVERSE  
                                  SKIP  
    OPERATION                   SENSING OF  
   __ CODE 7 _     CLA     SZA  BITS 5,6,7 HLT  
  /___ ___ ___\___/___\___/___\___/___\___/___\___  
  |   |   |   |   |   |   |   |   |   |   |   |   |  
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|  
  |___|___|___|___|___|___|___|___|___|___|___|___|  
              \   /   \   /   \   /   \   /   \   /  
            CONTAINS   SMA     SNL     OSR   CONTAINS  
             A 1 TO                           A 0 TO  
             SPECIFY                          SPECIFY  
             GROUP 2                          GROUP 2  

     Group 2 Operate Instruction Bit Assignments 
 

 
Boolean Condition
 GP2      LX7    0-6         SMA  
          BX6    X2  
          LX6    59-11 
          BX1    X7*X6 
          LX7    6-4         SNL 
          LX6    11-12 
          BX6    X6*X7 
          BX1    X1+X6 
          LX7    4-5         SZA 
          BX6    X0*X2 
          NZ     X6,GP2.1  
          BX1    X1+X7 
 GP2.1    LX7    5-3         SENSE OF TEST 
          BX1    X7-X1 
          LX1    1 
          MX6    -1  
          BX1    -X6*X1  
          IX5    X5+X1       INCR PC IF TRUE 
          BX5    X0*X5 
          LX7    3-7         CLA 
          PL     X7,GP2.2  
          BX2    -X0*X2  
 GP2.2    LX7    7-2         OSR 
          PL     X7,GP2.3  
          SA1    SR  
          BX2    X2+X1 
 GP2.3    LX7    2-1         HLT 
          PL     X7,INT1 
          EQ     INT0 
 
                                 GENERATES   GENERATES  
                                 AN IOP 4     AN IOP 1  
                                  PULSE AT    PULSE AT  
    OPERATION                      TIME 3     TIME 1  
                                   IF A 1     IF A 1  
   _ CODE 6  _  
  /___ ___ ___\___ ___ ___ ___ ___ ___/___\___/___\  
  |   |   |   |   |   |   |   |   |   |   |   |   |  
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|  
  |___|___|___|___|___|___|___|___|___|___|___|___|  
              \________        _______/   \   /  
                        DEVICE          GENERATES  
                       SELECTION         AN IOP 2  
                                         PULSE AT  
                                       EVENT TIME 2  
                                          IF A 1  

          IOT Instruction Bit Assignments 
 

 
Compound Dispatch 
Block Buffering
      SUBROUTINE PDP8IOT 

      (entry and dispatch) 
106   (returns) 

*  PAPER TAPE READER 
   
212   IF(NIP.NE.6) GOTO 216  
      CALL READBYT(1,LIB,5,IS) 
      NIP=1  
      IF(IS.EQ.0) GOTO 216 
      PRINT 214,IS 
214   FORMAT(' READ ERR: 'I2)  
      GOTO 404 
216   AC=LIB(NIP).OR.AC  
      NIP=NIP+1  
      GOTO 106 
   
*  PAPER TAPE PUNCH  
   
224   NOP=NOP+1  
      LOB(NOP)=AC  
      IF(NOP.LT.5) GOTO 106  
   
*  TELEPRINTER KEYBOARD  
   
230   IF(MD.EQ.6032B) GOTO 106 
      GOTO 404 
   
*  TELEPRINTER PRINTER 
   
243   IF(LSP.EQ.0) GOTO 244  
      NOP=NOP+1  
      LOB(NOP)=AC  
      IF(NOP.LT.5) GOTO 244  
      CALL WRITBYT(2,LOB,NOP,IS) 
      NOP=0  
244   IC=AC.AND.177B 
      IF(IC.EQ.15B) GOTO 246 
      IF(IC.LT.40B.OR.IC.EQ.177B) GOTO 106 
      IF(IC.GT.140B) IC=IC-40B 
      NTP=NTP+1  
      LTB(NTP)=ITR((IC.AND.77B)+1) 
      IF(NTP.LT.80) GOTO 106 

246   PRINT 245,(LTB(I1),I1=1,NTP) 
245   FORMAT(X80R1)  
      LTB=NTP=0  
      RETURN 

404   (errors)

 
 

Operations

The simulator reads commands from a file. Most commands correspond to front-panel switches or buttons. A few more control the loading or punching of tape at the teletype. The remainder measure and report progress within the simulation job.

ASR-33 Teletype

 
Command Loop 
Tail Sharing

*  COMMAND PROCESSING LOOP 
  
202   (Read and dispatch)  
  
* AC - ACCUMULATOR 
310   I2=AC  
312   PRINT 314,I1,I2  
314   FORMAT(XA2': 'O4)  
      GOTO 202 
  
* LO - LOAD ADDRESS  
320   PC=MA=SR 
      GOTO 202 
  
* CL - CLEAR 
330   AC=LK=0  
      GOTO202  
  
* CO - CONTINUE  
340   STEP=ISC 
      CALL INTRPT  
      CALL FLSHTP  
      GOTO 202 
  
* DE - DEPOSIT 
350   MD=SR  
      CALL STORE 
351   MA=PC=(MA+1).AND.7777B 
      GOTO 202 
  
* EX - EXAMINE 
360   CALL FETCH 
      PRINT 362,MA,MD  
362   FORMAT(' EX: 'O4XO4) 
      GOTO 351 
  
* HA - HALT  
370   CALL RI(ISC) 
      IF(ISC.EQ.0) ISC=-1  
      ISC=MIN0(ISC,777777B)  
      GOTO 202 
  
* MA - MEMORY ADDRESS  
380   I2=MA  
      GOTO 312 
  
* MD - MEMORY DATA 
390   I2=MD  
      GOTO 312 
  
* ST - STATUS  
400   I2=4000B*LK  
      GOTO 312 
  
* SW - SWITCH REGISTER 
410   CALL RO(SR)  
      SR=SR.AND.7777B  
      GOTO 202 
  
* PC - PROGRAM COUNTER 
420   I2=PC  
      GOTO 312 
  
* PR - PAPER TAPE READER 
430   I1=1 
      CALL FLSHPR  
432   CALL RC(I2)  
      CALL NEWNAME(I1,REPLTR(I2,1H ,0))  
      REWIND I1  
      GOTO 202 
  
* PP - PAPER TAPE PUNCH  
440   I1=2 
      CALL FLSHPP  
      ENDFILE I1 
      GOTO 432 
  
* TI - CPU TIME  
450   CALL SECOND(T1)  
      PRINT 452,T1 
452   FORMAT(' TI:'F8.3) 
      GOTO 202 
  
* RI - ENTER RIM LOADER  
460   DO 462 I1=1,16 
      MA=7755B+I1 $ MD=RIM(I1) 
462   CALL STORE 
      GOTO 202 
  
* PU - LOW SPEED PUNCH 
470   CALL RI(LSP) 
      IF(LSP.EQ.0) CALL FLSHPP 
      GOTO 202 
  
* ME - CONSOLE MESSAGE 
480   CALL RS(MSG,5) 
      CALL MESSAGE(MSG)  
      GOTO 202
 

Perspective

This program has been formatted to be read by a wider audience than originally intended. The original source was organized as a single file containing both FORTRAN and 6000 assembler. It contained SPACE and EJECT directives that exerted some control over the listing. The assembler listing would show how well the 15- to 30-bit instructions fit into the available 60-bits of each CDC word. A careful programmer also watches for functional unit conflicts and in-stack loops. 

The coding conventions were adapted from Greg Mansfield, author of the MACE operating system and many of the tools and utilities that ran on it. 

Some related files have been lost, notably the PAL-8 assembler binary and the hardware diagnostics tape. I wrote one command script with six or eight cards and never wrote another. This is missing too. 
 

Bibliography

Preserving Computing’s Past: Restoration and Simulation, 
Maxwell M. Burnet and Robert M. Supnik, 1996 
http://www.digital.com/DTJN02/DTJN02HM.HTM 

A PDP-8/E Simulator for the Apple Macintosh,  
Bernhard Baehr, 1998 
http://www.han.de/~bb/pdp8e/pdp8e.html 

Project: PDP-8 Computer, 
Barry J. Stern, [Java Applet; runs Focal] 
http://www.in.net/~bstern/PDP8/pdp8.html 

JavaScript PDP-8 Simulator
Neal Sample, University of Wyoming 
http://strawberry.uwyo.edu/~nsample/pdp8/main.htm 

JavaScript PDP-8 Assembler
Mark G. Arnold, University of Wyoming 
http://www.cs.uwyo.edu/~marnold/asm8.html 

DEC's 1967 PDP-8 Pocket Reference Card
A Programmer's Reference Manual for the PDP-8
Douglas W. Jones, University of Iowa 
http://www.cs.uiowa.edu/~jones/pdp8/refcard/67.html 
http://www.cs.uiowa.edu/~jones/pdp8/man/ 

A Seymour Cray Perspective 
Gordon Bell, 1997 
http://research.microsoft.com/~gbell/craytalk/sld001.htm 

Image Index 
Australian Computer Museum Society Inc 
http://www.terrigal.net.au/~acms/z00.htm 

Morse Code Receiver/Transmitter 
Ward Cunningham 
http://c2.com/~ward/morse/pdp8/ 

An Experiment in the Restoration and Preservation of Programs 
Ward Cunningham, 1998 
(in preparation)


© 1975, 1998, Ward Cunningham

all rights reserved