The java applet below is an emulator for a DEC PDP-8. It is running code for Lisp which was written for the PDP-8 family in the late 60's. The assembly code running here was last modified in May 1973. It was found on ftp.dbit.com, which contains a great collection of PDP-8 source and binaries originally found at on nickel.ucs.indiana.edu. I have also archived them here. The Lisp interpreter was assembled using Gary Messenbrink's PDP-8 assembler. The compiled code in bin format and the assembler's output listing are both available.
To use the emulator, wait until the applet loads and then click the "Run PDP-8" button below. The large text area on the left of the applet is performing the function of a PDP-8 teletype. You may click inside the text area to interact with the editor. The text aera does not automatically echo; the echo is provided by the lisp interpreter.
The lisp interpreter has a similar syntax to modern lisp interpreters, except at the top level. The interpreter does not quite use a standard read-eval-print loop, but instead looks for two items and then executes the first using the second as agruments. For example, to define a procedure to double a number and have it compute twice 21, you would type:
define(((double (lambda (x) (plus x x))))) (DOUBLE) double(21) 42
Note that the text in bold is the interpreter's reply. For a more comprehensize description of the lisp interpreter's use and primitives, including some information on its inner workings, see the documentation file. This file also includes the table of the interpreter's cryptic error codes.
The samples below were actually found with the lisp source files, and so were likely written with the interpreter itself.
DEFINE(( (MIN(LAMBDA (X Y) (COND ((NULL Y) X) ((LESSP X Y) X) (T Y)))) (SMALLEST (LAMBDA (X) (COND ((NULL X) NIL) (T (MIN (CAR X) (SMALLEST (CDR X))))))) (DELETE (LAMBDA (X Y) (COND ((NULL X) NIL) ((EQ (CAR X) Y) (CDR X)) (T (CONS (CAR X) (DELETE (CDR X) Y)))))) (SORT (LAMBDA (X) (COND ((NULL X) NIL) (T (COMB X (SMALLEST X)))))) (COMB (LAMBDA (X Y) (CONS Y (SORT (DELETE X Y))))) )) SORT ((10 9 8 3 7 5 6 1 2 4 ))
EXPR(1666 1374 3584) DEFINE(( (PASCAL (LAMBDA (N) (PROG (X R LINE Y Z) (SETQ X 0) OL(SETQ R 1)((LESSP N X)(RETURN NIL)) (SETQ LINE(LIST 1)) (SETQ Z X) IL((LESSP X R)(GO BX)) (SETQ Y(TIMES(CAR LINE)Z)) (SETQ Z(MINUS Z 1))(ZEXPR 2054 Y R) (SETQ LINE(CONS(EXPR 3172 15 -1)LINE)) (SETQ R(PLUS R 1))(GO IL) BX(PRINT LINE)(TERPRI)(SETQ X(PLUS X 1))(GO OL) ))) )) EXPR(3202 2536 1037) PASCAL(10)
The emulator defines the basic PDP-8 instruction set, as well as the capabilities provided by the extended memory unit and the teletype unit. No emulation for any other devices, as these were not necessary to run lisp. It is worth noting that on an actual PDP-8, loading the program into memory would have been a nontrivial process involving paper tape readers and entering a short program via toggle switches on the unit in order to load a program capable of reading the "BIN" format output by the assembler. My emulator simply reads the BIN file directly into memory.
The "text window" button opens a standard java text window, in which you can enter or paste text to be entered into the teletype. This is not a hack to the lisp code; instead, the emulator simply puts the first byte into the keyboard buffer and sets the keyboard flag to true. It then waits for the flag to be false (indicating that the program has read the keypress) then waits for another 40 PDP-8 cycles (since I obtained erratic results with any smaller number) and then repeats the process with the next character.
The text area beneath the four buttons provides status information about the PDP-8's state. The various registers and flags included are described below. Note that all numbers displayed in this window are in octal.
PC - the program counter
AC - the accumulator
KF - the keyboard flag is set when a key is pressed on the teletype keyboard. It must be programatically cleared
TF - the teleprinter flag is set after the teletype has finished printing the character in the teleprinter buffer
keybuf - contains the last key pressed
telebuf - contains the character to be printed to the teleprinter
DF - data field. the highest-order 3 bits of this 15-bit register are used to determine the field from which indirect operand fetches are obtained.
newIF - this field determines the next field from which to fetch instructions. The contents of this field are copied into the highest-order 3 bits of the PC after every jump instruction.
avg - this calculates the average time per instruction executed by the simulator. Though execution speeds varied throughout the PDP-8 line, 2-3us per instruction seems to have been a fair average. On my 550MHz Intel PIII running win2k, instructions seem to take between 6us and 12us to execute in the emulator.
Tim Gorton May, 2000