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:

  • The '8 bit octet' as the standard 'byte': Other byte lengths (CDC used 6 bits) were already being used by other computer systems. The octet, being what it is, could store a single ASCII character (7 bits). Graphics terminals often made use of custom character sets using the OTHER 128 available values (most significant bit set).

  • Low-endian storage of 16-bit values. That's right, the PDP-11 deviated from the 'mainframe' standard and stored its least significant byte FIRST within a 16-bit word. This was actually necessary in order to make word and byte instructions interchangeable. It also helps SIGNIFICANTLY when it comes to text processing. The 'low endian' concept carried over into the 8-bit microprocessor realm for Intel, Motorola, Zilog, MOS Technology, and others. From there, 'backward compatibility' kept it alive in 16-bit, 32-bit, and 64-bit processors.

  • DMA: Digital Equipment's 'UNIBUS™' allowed devices to take over and send data without having the CPU 'get involved'. It was the kind of architecture that would lead to ISA, PCI, and other 'standard bus' architectures we see in modern machines.

  • Extended Memory: The PDP-11 could ONLY access a 64k 'window' into address space. To accomodate the limitations, optional memory management hardware (and physical memory beyond 64kb) could be used to 'map in' a chunk of memory from a physical location to a 'virtual' one. This also allowed multiple processes to have their own memory space without the need to swap to disk on a context switch, and supported read-only and read/write 'chunks'. This is ALSO similar to how the x86 (and other) processors handle virtual memory, by using a relocation table that re-maps memory addresses from 'virtual' to 'physical', and only exposing the 'virtual' address to user applications. Great minds think alike, indeed.

  • Custom Hardware: DEC published the specification of the UNIBUS in hopes that people would develop custom hardware for it. They also made it POSSIBLE to modify the RT-11 operating system in order to write custom drivers for the custom hardware. THIS sort of 'open-ness' with standards (and sample code, and documentation) is the KEY to the success of embedded systems nowadays, particularly for those using operating systems like Linux and FreeRTOS, as well as the success of Microsoft® Windows™.

  • Graphical Displays: Although primitive, the 'VT' series terminals made 'visual editing' possible. DEC was not the ONLY company to do this. HP had their own standard as well. I don't know about IBM, but I would guess they had something, too. But the idea that a user would 'type in' things into a form, instead of using PUNCH CARDS, was a HUGE change, even revolutionary at the time. It made data entry possible without the use of expensive mechanical machinery. The average 'un-trained' warehouse clerk could do it. And the displayed 'data entry form' on the screen could make data entry a bit more intuitive (though the software author would have to 'make it happen'). It was, in many ways, the predecessor to a DIALOG BOX that you see so often in modern GUI operating environments.

  • UNIX™ and the 'C' programming language: The PDP-11 was the original development platform for the UNIX operating system and the 'C' programming language, which were developed concurrently. The intent of UNIX was to make an operating system that could be installed on MANY different hardware platforms. It made a lot of sense, considering how different many of these machines were, and the need for highly trained operators and programmers. You wouldn't have to re-learn everything from scratch when you changed jobs, or when the company changed hardware platforms, if you used the same cross-platform operating system every time. And as we know, Linux is based on UNIX, and BSD is a variant of UNIX, and OS/X uses the Mach kernel (derived from BSD at some point). And in the late 1970's, BSD-s IP stack became the essential STANDARD for the (then) Arpanet, which later became the Internet. So you can thank your operating systems and Intarwebs on the PDP-11.

  • The FIRST video game was written on the PDP-1. No kidding!

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.

  • SIMH PDP-11 (and other ancient computer) simulator (more info HERE) Typically available as a package/port on Linux, FreeBSD
    Additional links for Software (including operating systems)
    Link page for Computer History and Simulation HERE
    Other Notes: Press CTRL+E from the PDP-11 console to jump into the emulator where you can mount devices, or exit the program. You're welcome. I discovered this by hacking.

  • Disk images and software (tarballs, at least some of which are disk images with license info)
    In particular, I would recommend THIS one for use with SIMH (it works pretty well for me), though it is NOT Y2K compliant. The date isn't that important, though.

  • Additional binary image resources (licenses included in various directories)

  • PDP-11 library, another collection of PDP-11 disk images, primarily for RSX-11

  • PDP-11 Assembly Language (online catalog reference)

  • MACRO-11 Language Reference Manual (similar catalog reference)

  • 'Essential' Manuals (no links in this list, use on-line search for PDFs)
    NOTE: a LOT of them can be found HERE, already mentioned above
    • Introduction to RT-11
    • RT-11 Guide to Documentation
    • RT-11 System Release Notes
    • RT-11 Installation Guide
    • RT-11 Programmer's Reference Manual (very very important!)
    • PDP-11 MACRO-11 Language Reference Manual (also very very important)
    • PDP-11 Keypad Editor User's Guide
      if you get stuck in 'EDIT' and can't get out because you can't find the VT-100 keypad keys, use "SET EDIT EDIT" on reboot to avoid this and use the line editor instead, or modify the startup file to include 'SET EDIT EDIT'
    • RT-11 Keypad Editor Reference Card (quick reference for EDIT)
    • RT-11 System Utilities Manual (very very very important)
      Especially important are: PIP MACRO TYPE DIR HELP (yes, HELP). You can transfer files using 'PIP' and 'TYPE' by using a GUI operating system, then doing cut/paste to/from the console. It's slow, but effective.
      As an example, 'PIP FILE.TXT=TT:' is similar to 'COPY CON FILE.TXT' or 'cat >FILE.TXT' (CTRL+Z is EOF)
    • RT-11 System Generation Guide (if you want to customize the operating system, you CAN! It's like Linux's 'make config')
    • RT-11 System Internals Manual
    • RT-11 Volume And File Formats Manual (useful if you want to create/read native files and mount them in RT-11)
    • RT-11 IND Control Files Manual
    • RT-11 Software Support Manual

  • Punch Card reference (important for the PDP-11 card reader)


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.

  • INSTALLATION
    1. When the SIMH emulator starts, it will prompt you with '>'. You will need to mount a disk drive to boot from, and then boot it. The rtv53_rl.dsk disk image file works with the RL drive. The command sequence is:
          attach rl0 rtv53_rl.dsk
          boot rl0 rtv53_rl.dsk
      This will get you into the setup menu to install RT-11 on another disk drive.
    2. You will need to temporarily get back to the emulator's command environment to mount a 2nd disk. It's no problem at all to get back into the emulator and create a new disk image file.
      Simply press CTRL+E to get back to the emulator's command environment, then:
          attach rl1 os.new.dsk (follow any prompts)
          cont
      This will let you pick up from where you left off in the RT-11 install process.
    3. You will then be prompted to remove the disk, once the file copy is complete. Press CTRL+E again to get back to the emulator.
      Then, to unmount the volume, enter:
          detach rl1
          cont
    4. 'Rinse and repeat' for the backup disk, using a different mount file (such as os.backup.dsk).

    This should at least get you through the install process. You'll be creating an OS and a backup OS disk image. The backup OS disk image has all of the system files marked 'read only', so it's a bit of a pain to clone it and recover your OS that way. Instead you should just keep this file somewhere anyway and clone the disk image to back it up via 'cp -p' or 'copy' (depending on your host OS).

    After you have built (and backed up) your RT-11 image, which should have a few MB of storage available, you can boot it easily with a single command.
    1. First, exit the SIMH simulator, and create a file (I called mine 'boot.bat'). The disk image is 'os.dsk'.
          attach rl0 os.dsk
          attach rl1 data.dsk (this is optional)
          boot rl0
    2. Then, to boot your OS, use the command 'simh boot.bat' with appropriate paths (and name changes) applied to 'simh' and 'boot.bat' (in some cases the program is called 'simhv', you may need to prepend paths, and you might also need to run it from a particular directory, so Your Mileage May Vary on this one).

  • File Extensions: You probably recognize a few, but some have different meanings
    • COM files - these are COMMANDS, not executables, similar to CMD or BAT.
      STARTn.COM is used by the boot process. STARTX.COM is for FG/BG. STARTS.COM is for single-user mode. STARTM.COM is for multi-user mode. You'll probably start up in FG/BG mode by default. Changing the default is a little tricky. I recommend using the 'BOOT' command to re-boot into a particular mode. More on that later.
    • SYS files - operating system, bootup, and device drivers (loadable... yeah, loadable!)
    • SAV files - these are compiled programs, similar to 'EXE' in DOS or Windows.
    • REL files - similar to SAV files but can be loaded as a FG job (they're fully relocatable) Note that the concept of FG and BG is a little backwards - the default job, the system console, is "background".
    • MAC files - MACRO-11 source. Device drivers and whatnot are COMPILED, and these are the source files the system builder uses, like compiling a custom Linux or BSD kernel.

  • Commands: At the '.' command you can invoke a program in a few ways
    First, type the program name followed by arguments. Examples:
    • DIR *.MAC (lists all the '.MAC' files)
    • TYPE STARTX.COM (copies STARTX.COM to the console device)
      Alternately, you can use 'PIP TT:=STARTX.COM' (careful with PIP, it's unforgiving)
    • MACRO MYPROG.MAC (to assemble your program 'MYPROG.MAC' - creates MYPROG.OBJ)
      LINK MYPROG (to link the OBJ and create MYPROG.SAV which you can THEN run by typing 'MYPROG')
    Second, use 'R program' to start the program in 'interactive mode'. You will get a '*' prompt for arguments. To terminate the program and get back to the command interpreter's '.' prompt you'll have to use CTRL+C. Yeah, it's sort of bogus but that's the way it's done...
    Third, use 'RUN program' to run the program. The semantics between 'R' and 'RUN' are somewhat difficult to explain, and I'm not sure I fully understand it. RT[Fine]M on that one.

  • BATCH: There is a batch program called 'BATCH' that lets you set up control statements to run batch processes. Normally it would be driven by a card reader, but you can assign the 'BA' pseudo-device to read from whatever, if I remember correctly (I haven't experimented with BATCH yet, but I remember using it in High School, and it reads from "the default BATCH device", whatever you assign. RT[Fun]M again).

  • Transferring Files: Since there is no obvious way to transfer a file to or from the PDP 11 simulator, other than attaching a log to the console or using cut/paste via the host operating system and the 'PIP' program, I thought I might mention a few little tricks that I have used.

    • The tape device 'TM' (on the simh side) and 'MT' (on the RT11 side) is the best way to transfer a large number of files. I have written a utility called 'dectape' that makes transferring large numbers of files VERY easy. More information can be found at the github repository. In summary, you are using the magnetic tape device, and the 'dectape' utility translates between RT11 tape format and the host's file system.

    • The paper tape device lets you transfer files in BOTH directions! The down-side is that it requires CRLF line terminations, so on OS/X and BSD and Linux you'll need to convert your line endings from <CR;> or <LF> to <CRLF>.
      NOTE: for translating CRLF endings, THIS might help.
    • To copy a file from the host to the PDP-11 simulation using the 'Paper Tape' device:
      1. use CTRL+E to get into the simh monitor and enter this command to attach a file to the card reader:
            attach PTR filename.ext
            cont
      2. Then, from the '.' prompt in the simulated console, enter
            PIP filnam.ext=PC:

      3. When you are done, detach it from the card reader from the simh monitor (press CTRL+E again) by entering:
            detach PTR
            cont

    • To copy a file from the PDP-11 simulation to the host using the 'Paper Tape' device:
      1. use CTRL+E to get into the simh monitor and enter this command to attach a file to the card reader:
            attach PTP filename.ext
            cont
      2. Then, from the '.' prompt in the simulated console, enter
            PIP PC:=filnam.ext

      3. When you are done, detach it from the card reader from the simh monitor (press CTRL+E again) by entering:
            detach PTP
            cont

    • You can ALSO use a similar 'trick' by attaching an input file to the card reader device 'CR' or an output file to 'LPT' and THEN using PIP to transfer files in a similar fashion. On the 'simh' side, the devices are 'LPT' and 'CR'. On the RT-11 (simulation) side, they are 'CR:' and 'LP:'. Keep in mind that RT11 may translate lower case to upper case "for you". Unfortunately there's a bug in the card reader that only lets you transfer a single file (you have to exit the simulation to fix it). Upside, it's forgiving on line feeds and might be needed to test out the 'BATCH' system in the PDP-11 simulator. You can, however, set device mode parameters on various devices from the 'simh' monitor (and within RT-11) to prevent case translation. These values are a bit cryptic (values like '8b' for example), vary per device, and are documented in the (somewhat sparse) simh documentation and various RT-11 documentation. At least for the printer, you might include 'SET LP LC' (to allow lower case) in your 'STARTn.COM' file so that case shifting is turned off for the line printer device. Some programs, after all, may need a valid 'LP' device and as such, you might want to set it up this way by default.

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)

  • The SIMH application, which is what I use for emulating a PDP-11. Also good for other 'classic' architecture
  • Bootable Disk Images HERE and HERE and HERE and HERE and HERE, appear to be ok (licensed) for personal use
  • Another SIMH-related site, with information and screenshots.

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-2019 by Stewart~Frazier Tools, Inc.
Last Update: 10/05/2019

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