Digital Equipment Corporation's PDP-11

A public domain photograph of the PDP-11/40 - original https://en.wikipedia.org/wiki/File:Pdp-11-40.jpg

The Digital Equipment Corporation's PDP-11™ series were popular mini-computers in use from the early 1970's through the mid to late 1980's. Original PDP-11 computers were 'file cabinet' size. By the late 1980's, they easily fit on a desktop. Even Heathkit produced a PDP-11 home computer using an 'LSI' chip, and running their version of the RT-11 operating system. The acronym 'PDP' apparently comes from Programmed Data Processor. There are a lot of resources available online for these machines, and it's no wonder to me why that is: They are important in the history of modern computing.


Modern Standards That the DEC PDP Series Helped to Solidify

Back in the late 1950's and early 1960's, when the PDP series was born, there were competing standards for a number of computing concepts that nowadays are taken for granted. Because of the widespread popularity of the PDP series in businesses and in education, and the apparent influence on microcoprocessor development, many standards became, well, STANDARD in computing.

During the 1970's, Digital Equipment Corporation pretty much OWNED the government and educational computing market in the United States. Most likely it was because they offered competitive prices along with very good equipment and software. DECWriter consoles, a basic 300 baud dot matrix printer with an attached computer keyboard, were a VERY common site and made excellent operator consoles (since they logged everything onto paper). Because of their widespread use on college campuses, they were natural 'learning environments' for computer programming and computer science students (like myself). And they had support for the more popular compiled and interpreted languages, like FORTRAN and BASIC.

As a result, the PDP-11 was a major influence on modern computing. Some of the more obvious (and significant) developments that could be traced back to the PDP-11 include:

Emulation and Resources

If you are curious about the PDP-11 (and ancient mini-computers in general) there are emulators available, many of which are open source, and downloads for operating systems and documentation that have been licensed for personal and/or educational use without an license fees. We can probably thank HP and Compaq and Mentec Corporation for that, since they are the ones who own[ed] various parts of the Digital Equipment Corporation's intellectual property. However, as there are STILL commercial uses for the PDP-11 and its operating systems (nuclear reactor control systems are ONE area that I'm aware of), any commercial use would require a license of some kind.

Here is a SHORT LIST of resources that I found helpful. Some have direct links, some are simply names of resources that you can do an on-line search for (to get a downloadable PDF) file, some are 'catalog references' to manuals that you can download a PDF for if you do an online search. Nearly all of these are copyrighted in some form and permission may or may not be given to download them in PDF form. But they ARE out there.


A Few Useful Hints

There are a few things you might want to know before you try and set up your own emulator. As an example, I'll run through the process that I worked through with minimal documentation and what I remembered from 1979 and 1980.

So have fun playing with your simulated ancient computer! Or not.


MACRO-11 Code Examples

The PDP-11 had an assembler called 'MACRO-11'. It was a two-pass assembler, not unlike Microsoft®'s MASM&tm; assembler, but with fewer features and more limitations. But anyone familiar with MASM would recognize many of the SAME features, though Your Mileage May Vary when trying to write code with MACRO-11 if you are an experienced MASM coder.


Hello World

.TITLE HELLO
.MCALL .PRINT,.EXIT   ; tell assembler I want these two from SYSMAC.SML

START:  .PRINT #HELLO ; call OS function to print string, address HELLO
        .EXIT         ; call OS function to terminate the program

HELLO: .ASCIZ /HELLO, WORLD/ ; an ASCII string ending with a zero byte

.END START

Macros for PUSH and POP

;------------
; PUSH macro
;------------
.MACRO PUSH VAL
        MOV VAL,-(SP) ; store VAL onto the stack
.ENDM

;-----------
; POP macro
;-----------
.MACRO POP VAL
        MOV (SP)+,VAL ; pop item from stack, store in VAL
.ENDM

Macros for calling a function with parameters on the stack

;------------------------------------------------
; CALL macro - call a function (up to 26 params)
;------------------------------------------------
.MACRO CALL FUNC,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
PSHCTR=0
.IRP VV,<Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A>
.IF NB <VV>
; if the parameter is not blank, add 2 to the 'PUSHCTR' and push the value
; note that they push in REVERSE order so that the 1st param is always 4(R5)
; when the FNDEF macro is used, regardless of how many params are actually
; pushed.  this allows for variable length argument lists.
PSHCTR=PSHCTR+2
        PUSH VV
.ENDC
.ENDR
        JSR PC,FUNC
        ADD #PSHCTR,SP ; fix the stack on return
.ENDM CALL

Macros for defining functions (with parameters, compatible with CALL)

;---------------------------------------------------
; FNDEF macro - define a function (up to 26 params)
; function must exit/return with FNRET
;
; USAGE:  FNDEF function[,param[,param[...]]]
;         where 'function' is the label for the CALL
;          and  'param' lists stack parameters
; NOTE:  all stack parameters are 1 WORD each.
;---------------------------------------------------
.MACRO FNDEF FUNC,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
.MACRO .FNDEF CCC,VVV
CCC=VVV
.ENDM
FUNC:   PUSH R5
        MOV SP,R5  ; R5 is now the 'base pointer'  0(R5) == old R5
PRMCTR=2  ; for the parameters, points initially to pushed JSR
VARCTR=0  ; for automatic vars (resets stack pointer stuff)
          ; use the 'AVARS' and 'AVAR' macros following FNDEF
          ; (they are not valid outside of this context)
.IRP VV,<A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z>
.IF NB <VV>
PRMCTR=PRMCTR+2 ; must add 2 first so 1st param is 4(R5)
;VV=PRMCTR       ; reference the parameter as VV(R5)
        .FNDEF <VV>,\PRMCTR
.ENDC
.ENDR
.ENDM

;-------------------------------------------------------------------------
; FNRET macro - exit from a function.  R0 typically contains return value
;-------------------------------------------------------------------------
.MACRO FNRET
        MOV R5,SP  ; restore previous stack pointer
        POP R5
        RTS PC
.ENDM

Handling Automatic Variables

;---------------------------------------------------------
; AVARS macro - declaring MULTIPLE automatic variables
;               within an FNDEF context
;     (this only works for WORD variables)
;
; USAGE:  AVARS var[,var[,var[...]]]
;---------------------------------------------------------
.MACRO AVARS A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
.MACRO .AVARS QQQ
        SUB #QQQ,SP  ; make room for variables on stack
.ENDM
.MACRO .AVRS. NNN,VVV
NNN=VVV
.ENDM
; NOTE:  can be called more than once, but only within an FNDEF
;AVARSQ=VARCTR ; store current value
        .AVRS. <AVARSQ>,\VARCTR  ; assign to numeric value
.IRP VV,<A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z>
.IF NB <VV>
VARCTR=VARCTR-2
;VV=VARCTR ; reference variable as V(R5)
        .AVRS. <VV>,\VARCTR  ; subs numeric value for 'VARCTR'
.ENDC
.ENDR
AVARSQ=AVARSQ-VARCTR ; new value - I want the delta!
        .AVARS \AVARSQ  ; uses numeric value for 'AVARSQ'
.ENDM

;------------------------------------------------------------------
; AVAR macro - make room for a single variable of specific size
;              useful for arrays, structures, etc.
;              ONLY valid within an 'FNDEF' context
;
; USAGE: AVAR varname[,size]
;        where 'varname' specifies the name
;         and  'size' is the optional size (in words)
; to use the variable, reference it as 'varname(R5)'
; if a structure is involved, define the offset to
; the member and reference as 'varname+member(R5)'
; NOTE:  size CAN be zero (creates an alias)
;------------------------------------------------------------------
.MACRO AVAR NAME,SIZE ,?VV
.MACRO .AVAR NNN,VVV
NNN=VVV
.ENDM
VV=2
.IF NB <SIZE>
VV=SIZE+SIZE
.ENDC
.IF NE <SIZE>,<0>
VARCTR=VARCTR-VV
        SUB #VV,SP     ; make room for this one variable
.ENDC
;NAME=VARCTR ; reference variable as NAME(R5)
.AVAR <NAME>,\VARCTR
.ENDM

MEMSET and MEMCPY as macros

; -------------------------
; MEMSET - uses R0, R1, R2
; -------------------------
.MACRO MEMSET DST,BVAL,COUNT ,?L1,?L2
         PUSH R0
         PUSH R1
         PUSH R2
.IF NB <BVAL>
.IF DIF <BVAL>,<R1>
         MOV BVAL,R1
.ENDC
.ENDC
.IF NB <DST>
.IF DIF <DST>,<R0>
         MOV DST,R0
.ENDC
.ENDC
.IF NB <COUNT>
.IF DIF <COUNT>,<R2>
         MOV COUNT,R2
.ENDC
.ENDC
         TST R2            ; if count zero, skip loop
         BZ L2
L1:      MOVB R1,(R0)+     ; copy R1 (byte) into (R0)
         SOB R2,L1         ; use .MCALL SOB if processor has no SOB

L2:      POP R2
         POP R1
         POP R0
.ENDM


; -------------------------
; MEMCPY - uses R0, R1, R2
; -------------------------
.MACRO MEMCPY SRC,DST,COUNT ,?L1,?L2
         PUSH R0
         PUSH R1
         PUSH R2
.IF NB <DST>
.IF DIF <DST>,<R1>
         MOV DST,R1
.ENDC
.ENDC
.IF NB <SRC>
.IF DIF <SRC>,<R0>
         MOV SRC,R0
.ENDC
.ENDC
.IF NB <COUNT>
.IF DIF <COUNT>,<R2>
         MOV COUNT,R2
.ENDC
.ENDC
         TST R2            ; if count zero, skip loop
         BZ L2
L1:      MOVB (R0)+,(R1)+  ; copy (R0) into (R1)
         SOB R2,L1         ; use .MCALL SOB if processor has no SOB

L2:      POP R2
         POP R1
         POP R0
.ENDM

Sample usage of CALL and FNDEF as Hello World app

.TITLE FNTEST

.INCLUDE /MYMAC.MAC/ ; include macros (above) contained in 'mymac.mac'

FNDEF MAIN ; define main function 'MAIN' with no parameters
           ; using FNDEF creates a stack frame for automatic variables
           ; it also creates a label 'MAIN' that points to start code
        CALL MYPRINT,#MSG
        .EXIT

MSG:    .ASCIIZ /HELLO, WORLD/

.EVEN ; required if string has odd length (WORD alignment for code)

; automatic variables and pointers are numeric defines that are
; address offsets from R5.  To use them in an instruction or to
; pass them as a parameter, reference them as VARNAME(R5).
; If you need to get the address, you can do something like this
;       MOV R5,R0
;       ADD VARNAME,R0   ; R0 is assigned the address of VARNAME
;       MOV R0,VAR2(R5)  ; VAR2(R5) now contains address of VARNAME
; Note that R0 will always be 'nuked' by a function call.  Other
; registers should be preserved by PUSH, then POP before returning.
; The register PUSH should happen AFTER auto vars are declared, and
; the POP should happen right before FNRET.

FNDEF MYPRINT,ARG    ; defines function 'MYPRINT' with ARG as argument
      PUSH R1        ; sample, preserve R1 (isn't really being used)
      .PRINT ARG(R5) ; make OS call - ARG(R5) is string's address
      POP R1         ; sample, restore R1's value to what it was
      FNRET          ; stack cleanup and return

.END MAIN ; marks end of program with startup code at 'MAIN'


Additional Resources

SHORTER LIST of Emulation Resources (in addition to 'short list' above)


Copyrights, Trademarks, and other related legal stuff

Original photograph from top of page, licensed under Creative Commons and the GNU Free Documentation License.
The image file was copied to this server to avoid 'bandwidth theft' from wikipedia.
UNIX is a registered trademark by The Open Group


©2013-2016 by Stewart~Frazier Tools, Inc. - all rights reserved
Last Update: 3/11/2016

Back to S.F.T. Inc. main page