Thursday, 19 December 2024

Rediscovering the PDP-8


During my second summer at university, when I was 20, I worked for a local company that owned a DEC PDP-8 computer - in fact, two of them. The PDP-8 was the original minicomputer, sitting in just a single 19-inch rack as opposed to the whole building that our university ICL 1905 mainframe required. By today’s standards it was unimaginably constrained, with just 12K bytes of memory. Yet the company produced complex documents such as bills of materials on their PDP-8, for the architecture outfit that owned them.

They had started with a PDP8/I, and when I was there they had just acquired a newer PDP8/E, primarily as a way to get high-capacity disk storage using the RK05 removable disk. High capacity is a relative term. The disks held 2.5 megabytes of data - about a millionth of a modern hard disk, on a huge removable cartridge about 45 cm across.

My first job was to rewrite their existing sort program to use these new disks, which improved performance by a factor of about 100 due also to some moderately clever programming. My second job was my first taste of system level programming. DEC had supplied an interface between the two machines, allowing data to be passed both ways, but it came with no software at all. I wrote drivers allowing each machine to see the other’s peripherals as if they were directly attached. This meant that a program could access the new disks as well as the older peripherals on the PDP8/I, such as the lineprinter and high speed paper tape reader and punch.

Back at university, there was another PDP8/I, with a graphics display built around a Tektronix storage tube (the KV8I). I took advantage of that to implement Conway’s Game of Life, squeezing as much functionality and capacity as I could into the machine’s 8K 12-bit words. That became my final year project for my Computer Science degree. It really pushed to the limit what could be done with such a tiny machine. Many years later I rewrote my program in C++ for Windows as Winlife32, still available on the web and downloaded from time to time.

A Career at DEC

My summer vacation job turned out to have a big influence on my career and the rest of my life. I really enjoyed working with the DEC machines, and when it came time to look for a job a year later I applied to them. I had no idea what jobs might be available, so I pretty much said, “Do you have any jobs for a new graduate?”. As it turned out, the senior programmer at the vacation job had moved to DEC in the meantime, and gave me (I suppose) a glowing reference. DEC offered me a job, in their small European software development in Reading. It had the highest salary of the various jobs I’d applied for, and on that basis I went to work for them. I spent the following 20 years working at DEC, on the IAS operating system and several network products, and enjoyed nearly every day I worked there.

But the PDP-8 was at the end of its life. It had been replaced by the larger and much more capable PDP-11, and all my work was for that until it was in turn replaced by the VAX a few years later. We didn’t even have a PDP-8 in Reading. So that was the last I saw of it.

The PDP-8 had a very clever architecture. With a 12-bit word it could only find space for 6 different memory-access instructions. The two most basic memory-access instructions, from the 1950s until now, are LOAD and STORE, to move a value between memory and a register. The PDP-8 had neither. LOAD was replaced by ADD, which added the memory value to the accumulator. To load a value, you first had to make sure the accumulator was already zero. There was an instruction to do that, but the STORE instruction was replaced by DCA (Deposit and Clear Accumulator), which also left the accumulator clear. This substantially reduced the number of instructions which would otherwise be needed to clear it explicitly, though it can catch you out.

In addition to the 6 memory-access instructions, it had a bewildering variety of “microcoded” instructions, where setting various bits would do things in a well defined sequence. For example the sequence “CLA CLL CMA RAL” would clear the accumulator, complement it, and rotate it left without introducing a low order bit, leaving the octal value 7776, or -2. Others would skip the next instruction based on some condition, so for example to jump somewhere if the accumulator is zero, you would write SNA (skip if non zero) followed by an unconditional jump.

My project to connect the two PDP-8s led to an interesting discovery. The hardware involved wasn’t a standard product. It had been specially built for us by DEC’s custom hardware group (CSS) in Reading. Sometimes my code worked perfectly. Other times it would hang in mysterious ways. Finally I attacked the hardware itself, with the only equipment we had - an old-fashioned, huge Avo multimeter. Carefully following the schematics that had been supplied with it, I attached a probe to a pin to see whether it was on (5V) or off (0V). It showed about 3.5V, halfway in between. In a digital circuit, this is impossible. Further probing showed that the “5V” power supply rail was in fact at 3.5V. With a bit more tracing, I discovered that the unit had been built for 220V, but had been connected to the internal 110V transformer.

That explained why it worked sometimes and not others. If the mains voltage was high, for example mid-afternoon, then the “5V” supply reached just high enough to make things work. But at lunchtime or late afternoon, when the power demand was higher and the voltage was a bit lower, the poor thing just couldn’t quite get its logic circuits to work.

A call to DEC, and a visit from their very apologetic engineer, fixed things. After that my software worked perfectly.

A New PDP-8

My PDP-8 knowledge remained lurking in a back corner of my mind for 50 years. A few years ago someone produced the PiDP8, emulating the PDP-8 hardware on a Raspberry Pi and completing that with a 2/3 scale replica of a real PDP-8/I front panel, all 92 lamps and 21 switches of it. Later they did the same for the PDP-11/70, and just recently for the 36-bit PDP-10. A friend of mine has a PiDP11 running the IAS operating system that I worked on soon after joining DEC.

The emulation uses Bob Supnik’s SIMH system. He has been maintaining and extending this ever since long before demise of DEC in around 2000. It can emulate every system ever made by DEC, and dozens of others too. It also understands all the common peripherals, so you can connect simulated disks, tapes and paper tape.

And then a week ago, completely unexpectedly, a friend gave me a PiDP8. The panel comes in kit form, so every one of those 92 lamps and 21 switches has to be soldered into a board, along with a few auxiliary components. That took a couple of days to complete. Meanwhile, I already had a Raspberry Pi4 left over from another project. Amazingly, after 4 years in a cardboard box, it booted up and after a couple of hours was updated with all the latest software.

Installing the PiDP8 software package on the Pi was straightforward, and I got it running - without the unfinished front panel - with no difficulties. Later, though, when I did connect the panel, I ran into a problem. All the lights worked perfectly, but the switches showed a bogus value. This is mentioned in the instructions, which explain that a patch needs to be applied when using the Pi4. So far, so good.

However finding the patch was another story. A quick search found the instructions, but they involved a mysterious source management package called Fossil. Trying to run it showed that the PiDP8 software distribution includes all the sources, but not structured as a Fossil repository - so Fossil won’t run. I have no idea how to use Fossil, and zero interest in learning yet another alternative to Git. Luckily, more searching found the one file that needs to be updated, and it was easy enough to rebuild with the new file.

That done, I had a working PiDP8. The package includes not only the emulator, but also the OS/8 operating system and all associated utilities. Everything worked. But now the question was, what to do with it?  It comes with a few simple games written in Basic. They’re fun for a few minutes but the retro-novelty quickly wears off. The PDP-11 operating systems I worked on all rotated lights on the front panel to make a familiar pattern when the machine was idle, so in a bout of PDP-11 nostalgia I decided to make my PDP-8 do the same thing. (OS/8’s null job is a two-instruction loop that does nothing at all. Memory was much too precious to waste on frivolities).

Rediscovering PDP-8 Assembler

It has been a long time - well over 20 years - since I have written more than the odd line of assembler, for any machine, though I’m familiar with reading it for the x86. The first step was to figure out the logistics of programming the machine. Full nostalgia would have required me to use OS/8’s very primitive text editor. In the 1960s that was an enormous improvement on editing paper type using the ASR33, as we did for the computer I used at school. But that was a step too far

I would create code on the host Raspberry Pi using my regular editor, Emacs - itself pretty retro but I’m used to it and haven’t yet found anything significantly better. I could also assemble it there, using the Palabert port of the PDP-8 assembler. But then I had to move the binary file to the PiDP-8.

A bit of searching showed that the simulator allows you to turn a host file into a simulated paper tape. The PDP-8 PIP program can be used then to read the “paper tape” into a file. (PIP was the standard file management utility on all the DEC systems until VAX). But, as I quickly discovered, it will only transfer text files, not binary. The obvious solution was to transfer the text file, then assemble it with the native PAL assembler.

That still left one problem. In an age when Unicode can represent every known alphabet, thousands of emojis and other weird stuff like ⨔, it’s easy to forget that not so long ago even lower case letters were a rare luxury. The PDP-8’s 12-bit word could hold two 6-bit characters, permitting only upper-case letters. Writing code in upper case is painful, so instead I wrote a little Python program to convert to from lower case, and also to change the line ending to CR-LF. In the days of ASR33 teletypes, these characters physically instructed the machine to move the carriage and roll the paper up, and the PDP-8 utilities expect them.

Finally I could try my code out. It was surprisingly hard to get it to work correctly. Programming the PDP-8 requires a special mindset, which in my case had evaporated over the last 50 years. Numerous times I forgot to clear the accumulator before loading it with TAD, or tried to reuse it after a DCA. I had to re-learn use of the so-called microcoded instructions. For example, to negate the accumulator (often needed since there is no subtract instruction) requires CMA IAC - complement and then increment the accumulator, forming the twos-complement. The CLA element clears the accumulator at the start of one group, but at the end of another group. There’s a good reason for this - the PDP-8 instruction set is truly ingenious. But you have to get your head round it.

Surprisingly, I found my 1970 Small Computer Handbook, which was helpful. Despite the very generic name, it was a complete manual for the PDP-8, describing not only the instruction set in great detail, but also every single one of the numerous available peripherals.

Modern debuggers and IDEs are extremely powerful. The PDP-8 just had ODT (for Octal Debugging Technique), a simplification of the PDP-10's symbolic debugger DDT (a backronym for Decimal Debugging Technique, but really named after the then-universal insecticide, for getting rid of bugs). ODT lets you set a single breakpoint, and requires you to do everything using octal addresses, with an assembler listing in front of you. But for my simple light-twirler it was perfectly adequate.

There was one bug that took me a long time to track down, which turned out to be a function that returned to the wrong place. I’d completely forgotten that there are 8 memory locations (0010-0017) that autoincrement when you use them as index registers for an indirect memory access.  And I was using one to store the return address from a complicated function. So when it executed the usual return instruction - JMP I XXX - it first incremented the return address, then returned, thereby skipping the first instruction after the call. The fix was simple enough, don’t use those autoincrement locations for anything else. They’re there to reduce the amount of code needed to do, for example, a block memory copy - another ingenuity of the PDP-8.

A Working PiDP8/I

I couldn’t stop myself tweaking the program, to twirl the lights in various randomly chosen ways. That done, all I had to do was finish the assembly of the physical machine. Normally the Raspberry Pi is accessed through SSH or, if graphics are required, VNC. But it seems a good idea to be able to access it directly - networks are never to be trusted! So I added tails to the USB, HDMI and power connectors, bringing them out through a slot in the base of the case.

Indispensible tools: Panavise board vice, Antex
temperature controlled soldering iron, desoldering tool

I should add that the PiDP8 kit is really excellent. The instructions are very comprehensive, all the parts were present with even some spares, and everything is very high quality. It's a lot of soldering, 92 LEDs, 21 switches, and various other bits. It is much easier if you have a suitable board vice, and a powerful temperature-controlled soldering iron.

Now my PiDP8 sits on the corner of my desk, next to my 1950s-vintage Olivetti Divisumma and my Nixie tube clock. Its simulated incandescent light bulbs twirl gently in a constant reminder of a nearly-forgotten era of computing.

If you have a PiDP8 and want to see your own lights twirling, the program is available on github.

A retro-collection: my Nixie tube clock, the PiDP8, and my Olivetti Divisumma