PDP2011 Overview

This website describes my project, PDP2011 – a re-creation of the well known series of PDP-11 computer systems in VHDL. Everything that is needed to run a complete PDP-11 system is included; you can run a complete Unibus PDP-11 system with console, disks and other peripherals on a simple low cost FPGA development board. The original V5-V7 versions of Unix, BSD 2.11, and the original DEC operating systems for the PDP-11 work. (*)

Current status

  • The CPU model is configurable, from the smallest 11/10 up to J-11 systems. Model-specific exceptions are implemented to the point that many of the original XXDP MAINDEC test programs run without error, and the original model detection code embedded in several operating systems in most cases correctly identifies the configured model.
  • The memory management unit is automatically included if the CPU model can support it, does 18- or 22 bit translation and supports separate instruction and data spaces, as well as kernel, supervisor and user mode. For the 11/45 and 11/70, the 3-bit ACF is implemented including memory management traps and A- and W-bits; all other models have the later, simpler version of memory management based on a 2-bit ACF. The special maintenance mode is also implemented – this makes it possible to run the original XXDP test programs to verify that the MMU works correctly. For the 22-bit processor models the Unibus map is included in the memory management unit.
  • Model-specific optional instructions, like SPL, MARK, MxPx, MxPS, MFPT, CSM etc. are present according to the CPU model.
  • J-11, 11/45 and 11/70 have the dual general purpose register set.
  • The EIS instructions: MUL, DIV, ASH, ASHC, and XOR are available if the CPU model supports them.
  • The floating point processor is complete, and is included by default with the CPU models that it could optionally be installed in. It can be disabled too, for instance to save FPGA resources.
  • RK11 and RL11 disk controllers work and use SD cards to store the disk data on. Up to 8 RK05 or 4 RL02 disks can be emulated on a single SD card.
  • If the RK or RL disks are too small, then there is the option to configure a RH70 (for 11/70) or RH11 controller with a single RP04, RM05, or RP06 disk. The disk data for the RM or RP disk is also stored on a SD card.
  • A KW11L line clock is present; by default it is configured at 60Hz, but 50Hz and 400Hz are also possible.
  • Up to four serial lines for console and terminals can be configured.
  • A DEUNA/DELUA compatible core is available; the DEUNA core is a front end for a ENC424J600 ethernet chip, which does most of the ‘real’ ethernet work. Digilent’s PMODNIC100 contains the ENC424J600 chip, and can be easily connected to FPGA boards.
  • If the FPGA board includes ps2 and vga ports, a simple terminal can be added to the FPGA core so you don’t need a pc with hyperterm or minicom to run a PDP-11. The CPU that runs the software for the terminal is of course also a PDP-11.
  • Everything is verified in hardware, on both Altera and Xilinx boards. The VHDL is not vendor specific, so it should be possible to make it work on any FPGA that is large enough with only minor changes in the top level VHDL to map the board resources like connectors, blinkenlights and memories to the core. Several top level VHDL files and tool chain project definitions are available for popular development boards from Terasic and Digilent.
System memory map
The systems that are generated from the VHDL that implement the CPU, MMU, control registers and peripherals contain many memory-accessible registers that are specific to the model that is configured, or to the peripherals included in it. A summary memory map of the most important addresses is as follows:
Type    Address     Vector    Description
-       17 777 776  -         PSW - Program status word
-       17 777 774  -         Stack limit register
-       17 777 772  -         PIRQ - Software IRQ register
-       17 777 766  -         CER - CPU Error Register
-       17 777 640  -         MMU User mode PAR
-       17 777 600  -         MMU User mode PDR
-       17 777 576  -         MMU SR2
-       17 777 574  -         MMU SR1
-       17 777 572  -         MMU SR0
-       17 777 570  -         Console switch and display register
KL11    17 777 560  60/64/4   KL11 Console serial line
KW11L   17 777 546  100/6     KW-11L Line clock - default 60Hz
RK11    17 777 400  220/5     RK11 RK05 Disk controller
RH11/70 17 776 700  254/5     RH11/RH70 Mass bus controller - RP/RM disk
KL11    17 776 500  300/304/4 KL11 optional 2nd serial line
KL11    17 776 510  310/314/4 KL11 optional 3rd serial line
KL11    17 776 520  320/324/4 KL11 optional 4th serial line
XU      17 774 510  120/5     DEUNA controller
RL11    17 774 400  160/5     RL11 RL02 disk controller
M9312   17 773 000  -         M9312-style bootrom
-       17 772 516  -         MMU SR3
-       17 772 340  -         MMU Kernel mode PAR
-       17 772 300  -         MMU Kernel mode PDR
-       17 772 240  -         MMU Supervisor mode PAR
-       17 772 200  -         MMU Supervisor mode PDR
-       17 770 200  -         Unibus map registers
Disk images
The disk controllers – RK, RL and Massbus RP or RM – all store the disk data on SD cards. Currently, only basic SD cards are supported by the controllers – SDHC or SDXC will not work, and even some SD cards may be problematic, since the controllers hardly bother with error checking or card status codes. I mostly get the best result with Sandisk branded cards; others seem to have a problem with the speed of initialization sequence, which I have not implemented according to the official specification. This might in some cases be solved by running the system at a low speed, like 1Mhz.
The card images are stored linearly, sector by sector, from the start of the SD card – ie, there is no master boot record on the SD card, nor is there a partition table. For the controllers that support multiple images (ie, RK and RL), the images are stored sequentially; that is, the RK1 image sector 0, track 0, cylinder 0 is stored directly after the last sector of the last track on the last cylinder of RK0.

The RL controller is a bit more special, in that the RL has 256-byte sectors, while the SD card standard only allows for 512-byte sectors. This mismatch is solved in that the controller only reads or writes the first half of each SD card sector, and leaves the rest blank. This means that ‘real’ RL disk images must be converted to the 256-byte payload,256-byte blank SD card format. I’ve written a trivially simple C program to do that; it is called sdfmt. It takes two parameters: -i (which may occur multiple times) names the input image file; -o names the output image file, that is to be copied to an SD card.

The Massbuss disk controller supports RM05, RP04 and RP06 drives; however, only the RP06 has really been tested. I expect that the other types will probably work, since most differences are in the disk geometry and thus the only place where the controller source needs to cope with differences is in the sector calculation. It should not be too difficult either to add the other RM and RP types as well – but, since RP06 is widely supported in the software and big enough for most use, this is not really at the top of my priority list.

Writing the original disk images, or new disk images created by SIMH, to SD cards is a bit tricky. On Linux, you typically do this with the dd command, and make a plain one to one copy of the disk image to SD card, for instance using a USB card reader/writer. Many laptops also come with a SD card slot built in. The tricky bit is however to find out the device name of the SD card slot, and be *very* sure that you have the right one. Look in your mounted disk table; any device you see here you should *not* use on the dd command. Then connect the card, look in the syslog to see which device was just connected, make sure that it has not been taken by an automounter (if so, just unmount it) and make very sure you’re not confused by something else. If you make a mistake here, you *will* lose data; the dd command will just overwrite anything that is on the device that you tell it to, even if that is a partition table. You may very well mess up your entire primary hard disk and lose all data on it.

For Linux systems, something like

dd if=unix_v5_rk.dsk of=/dev/sdc

will create a Unix V5 disk image on a SD card, *if your card reader is mapped to /dev/sdc*. Again, *please* be sure you know what you’re doing, because you can really lose your data with a very simple mistake in this command.

Similarly,

sdfmt -i unix_v7_rl.dsk -o v7.rl
dd if=v7.rl of=/dev/sdc

will create an RL02-formatted image of V7 unix. Again, please be sure that the dd command refers to the right device.

I don’t ever use anything else but Linux for this kind of work, so I don’t know how to create images with Mac OS or Windows.

Serial links

The current serial link controller is KL11-like; it is the most basic serial controller that was typically used to connect the console to. The baud rate is by default set to 9600, 8 bits, no parity; the baud rate can be defined in the VHDL, but is not software selectable. Usually, the most significant bit of all output bytes is forced to 0 by the hardware – so actually only 7-bit characters are sent out.The same VHDL is used for both the primary port (the one at address 17777560) as well as additional ports that can be configured in the top level source. The primary port is usually connected to the most obvious DB9 port on the FPGA board – if one is available.

Known problems
There are no major problems anymore, everything seems quite stable and reliable. Only one issue remains on the list of known problems:

  • RT-11 V5.3 crashes during the boot from the original RL02 distribution images. When the files are copied over to an RK05 image, the boot is ok however.
Todo list
  • A more extensive boot rom implementation, that runs more elaborate diagnostics and hardware identification at initial boot, and allows for a dialog that lets the operator choose from which device to boot.
  • A somewhat more VT100 like terminal – mainly, this can be done by improving the assembler code for the terminal somewhat.
  • An improved SD card interface for the disk controllers, where the card communication is decoupled from the memory interface. This would make it possible to release the CPU during the card communication – so the systems would appear to be more responsive. It would also solve one of the major differences between this core and real hardware – PDP11 were known for their fast response to interrupts. This core however can remain unresponsive to any interrupt as long as a disk controller remains bus master. Which translates to the maximum time that the connected SD card is busy processing a command.
  • An improved SD card controller, that allows for SDHC cards, maybe also for SDXC cards, and implements error checking on all card types. The card initialization should allow for slower cards to be correctly initialized.
  • A JTAG interface to look into the CPU’s registers and control variables while it is running, single-stepping or halting the cpu, instruction history, etc… Also probably a lot of work.
Implementation

With a few small exceptions, the source files are structured along the major components in a complete system – the CPU and MMU are described each in one source file, as are all the peripherals. All of these are connected in a large source called Unibus. The Unibus component in turn is instantiated in a top level source that deals with the specific stuff needed to make the VHDL fit to an FPGA board – like, driving the memory and the ‘real’ peripherals. One special item to mention is the M9312-style boot rom, which has a tiny bit of code that will bootstrap the system from the first available disk controller.

The CPU is by far the most complex source; it contains the main state machine for the CPU, and also for the FPU and the optional instructions. The main task for the state machine besides sequencing through the instruction ‘microsteps’ is to drive the bus signals; reading from and writing to memory. The three separate ALU’s for the regular instructions, the EIS instructions, and for the FPU are also in the CPU source.

The memory management unit is in comparison fairly simple; it contains a large number of control registers, and a few rather complex adders that generate several versions of the physical access. Also in the memory management unit is the black magic of the Unibus map, and the tricks it requires to connect peripherals onto a bus that is somewhat separate from the ‘real’ memory bus, but still the same if mapped through the Unibus map.

All three disk controllers basically follow the same model; they have a state machine for interfacing the SD card, and a set of control registers that will cause the state machine to start to work when the correct bits are read or written. The differences are mainly in the control registers, in the sector size (256 for RL, 512 for the others), and in the disk track and cylinder to sd card sector calculation.

In- and excluding specific parts of the CPU, MMU, or even entire peripherals to implement the different functions of the different PDP11 system models is done by regular signals and if-then-else statements – the compilers and optimizers do an excellent job of turning this into efficient core; there seems to be very little overhead as a result of this coding style. I’ve not really tried to write very resource efficient core either. The VHDL coding style is simple – maybe even naive, and probably violating a lot of coding best practices. In my own defence, I should probably say that this is the first design I’ve worked on that is more complex than pushing buttons to turn leds on and off.

Source organization

The sources and other files are organized in a fairly flat directory. The main VHDL sources, Macro-11 sources for the bootstraps, test programs and terminal are in the top level directory. The tools – Richard Krehbiel’s Macro-11 etc – are in a subdirectory.

Every board that I use is defined in a subdirectory; these subdirectories contain the top level VHDL source for that board, and also any board-specific VHDL if required. See the page titled ‘Files’ for a more detailed explanation of what each file is.

Performance

The goal that I set has been to get the VHDL to work, and as correct as possible – not to get the maximum speed out of it; any speed ‘correct for the period’ is really good enough. Having said that, I’m obviously very happy and proud that the CPU is in most cases considerably faster than the original models. It could have been a lot faster still, if I had not made a major mistake in the design of the memory interface very early in development; some of the memory access runs at half cycle – which I thought at the time was a smart trick to make it go faster, but I realize now that I actually did the opposite. To remove this mistake would mean almost a complete redesign though, and I’m not going to.

Walter’s w11 is a lot faster though. When compared to this table, where w11 reaches 160-168 Hanoi’s per second, pdp2011 reaches about 38 with the CPU running at 10 Mhz, which is not the maximum speed I’ve ever been able to get, but a decent baseline that is stable on most boards. I’ve not yet been able to compile the Dhrystone test yet, so the numbers for that cannot be compared. Still, looking at the Hanoi number for 11/53+, pdp2011 is about three times as fast as that.

License

The copyrights to the VHDL described on this site are held by me. Basically, you can run the core for personal use, but you cannot use it commercially. See the licence description in the source files for more information.

Other PDP-11 projects

  • POP11, created by Yoshihiro Iida at the Tokai University of Japan; it is a PDP-11/40 that runs Unix V6. It’s implemented in SFL, a language that is used to generate Verilog. There appear to be no recent developments, but it was probably the first working PDP-11 in a FPGA capable of running Unix.
  • Brad Parker‘s Verilog PDP-11, a 11/34 that is verified to be correct by running it in simulation alongside SIMH.
  • Walter Müller‘s w11, which currently is an 11/70 in VHDL, including a real cache implementation and capable of impressive speed.
  • And of course SIMH, the brilliant simulator by Bob Supnik that is a reference for all things PDP-11 and a lot more.
Brad, Walter and I worked on a similar time schedule, but we were not aware of each others work until I saw some questions from Brad on the alt.sys.pdp11 newsgroup, and until shortly after that Walter put his work on opencores. Probably they were as surprised as I was to learn of the others. What is good to see is that the three of us all have different strenghts, and have taken a different approach as well; it means that there is a lot that can be learned from the three projects.
I have heard of one more implementation, but it is a commercial project that is not disclosed.

Thanks

Several people I’ve never even talked to or emailed with have still contributed to this project. I owe a big thankyou to Al Kossow for running bitsavers.org, with it’s enormous amount of documentation and software. Without access to this information, the project would not have been possible at all. But I also would like to thank to some slightly less famous people, like John Kent, and Tim Boscke whose work taught me the first basics of how to make a CPU work; and Bill Buzbee for inspiring me to start working on my own blinkenlights project.

Copyright footnote (*)
Note that copyrights may still be active on the operating systems and other software that can run on the hardware described on this website. I do not advocate or promote violating these copyrights. If you decide to do so, any consequences are yours to deal with.