https://github.com/skx/cpmulator/
Over the past few days I've seen posts on hacker news discussion 6502 assembly, people coming to the infocom games, and similar things. There's a lot of interest out there in this retro stuff, even now.
https://github.com/skx/cpmulator/
Over the past few days I've seen posts on hacker news discussion 6502 assembly, people coming to the infocom games, and similar things. There's a lot of interest out there in this retro stuff, even now.
It's essentially impossible for a single person to build something as complex as a modern PC "from scratch", or indeed to build an operating system that compares to Windows, Linux, or MacOS.
These old microcomputer systems are simple enough for one person or a small team to understand and build, and they are/were capable of doing "useful work", too, and not so overly-abstracted like some "teaching systems" are.
I think that for me, part of the point of digging into something like the p-System is to show some of the brilliant (and stupid) ideas that went into building something as ambitious as a "universal operating system" in the mid-1970s.
Having to remember where I'd put the relevant chunk of assembler any time I needed a division routine was, admittedly, less fun, but the memories remain fond nevertheless :)
You probably remember Gary did start selling an MS-DOS clone (DR-DOS) after a few years, when it became clear CP/M-86 was dead. IIRC that's what inspired Microsoft to start working on MS-DOS again after several years of letting it languish. They also put anti-DR-DOS code into Windows so you couldn't start it up on DR-DOS.
And, as you know, there were a number of other bare-bones "operating systems" like MS-DOS and CP/M in those days: HDOS, TRS-DOS, ProDOS, etc. But once everyone was writing their apps for MS-DOS, there was little point in bringing out a new OS that wasn't compatible with it unless it was dramatically better in some way.
So, why weren't there other members of what set?
Make a free open source one.
There were lots of disk operating systems created for 8 and 16-bit machines, as well as a number of BASIC + DOS type systems. But CP/M is the one 8-bit OS to rule them all - even running on an Apple II or C64 with a Z-80 CPU card or cartridge.
CP/M was little different from the PDP-11 operating system, which it used as a model.
CP/M was not as innovative as often thought.
Both CP/M-86 and MSDOS were just an interrupt table and some implementation routines. The 8086 chip was designed around that interrupt table, so of course any OS would use it.
Looking at https://bitsavers.org/pdf/dec/pdp11/rt11/v1_Sep73/DEC-11-ORT... (RT-11 System Reference Manual, DEC-11-ORUGA-A-D, Sept. 1973, Chapter 8, Programmed Requests) I see printing of ASCIZ strings, 16 numbered I/O channels for open files, stream (wordwise) rather than purely blockwise access to those files (though the start position is specified as a block number), an open set of device names, RADIX-50 filenames, the ability to "swap" the "user service routines" into memory temporarily so they don't have to be resident the whole time your program is running, and "tentative files" that automatically replace a permanent file if successfully closed, and asynchronous I/O (.READ and .WRITE as opposed to .READW and .WRITW or .READC and .WRITC); all of these would have been improvements over the design CP/M actually used. On the other hand, it says RT-11 only supported contiguous storage of files (like the p-System), a CRLF is automatically appended to any string you print, and the filenames are 6 characters rather than 8, which are points where CP/M wins.
The whole FCB thing, which is about 80% of CP/M BDOS, seems to have been absent in the RT-11 system call interface. I'm not sure whether it's better or worse (it's substantially more painful to use, but permits your program to allocate space for the number of open files it's actually going to use) but it's certainly a very different approach. RT-11 has .SAVESTATUS and .REOPEN to work around the 16-file limitation when necessary.
Because you can only read or write starting at a block boundary in RT-11, it seems like it usually wouldn't make sense to read less than a block. But the inability to read more than a block was a real bottleneck for I/O in CP/M, as Tim Paterson explains in the blog post I linked from https://news.ycombinator.com/item?id=43729165:
> At least part of the reason CP/M was so much slower was because of its poor interface to the low-level “device driver” software. CP/M called this the BIOS (for Basic Input/Output System). Reading a single disk sector required five separate requests, and only one sector could be requested at a time. (The five requests were Select Disk, Set Track, Set Sector, Set Memory Address, and finally Read Sector. I don’t know if all five were needed for every Read if, say, the disk or memory address were the same.)
(Actually, this is the BIOS interface; I think the BDOS interface was more reasonable, but still only able to read one 128-byte record at a time.)
Even the "Keyboard Monitor" described in Chapter 2 sounds very different from the CP/M command processor, for example, using "." as its prompt, supporting user-defined device names and command abbreviation, being able to make octal dumps of RAM and change its contents byte by byte, requiring an explicit "run" command to run programs, no way to pass command-line arguments to programs, and echoing character deletion in a teletype-friendly fashion\noihsaf\format. Most of the control keys are the same, I guess? And the editor sounds pretty similar to CP/M's benighted ED?
> We knew Digital Research was working on a 16-bit OS, CP/M-86. At one point we were expecting it to be available at the end of 1979. Had it made its debut at any time before DOS was working, the DOS project would have been dropped. SCP wanted to be a hardware company, not a software company.
Oscar Toledo G. also wrote a similar graphical operating system in the 01990s and early 02000s, working on the computers his family designed and built (though using off-the-shelf CPUs). You can see a screenshot of the browser at http://www.biyubi.com/art30.html and read some of his reflections on the C compiler he wrote for the Transputer in his recent blog post at https://nanochess.org/transputer_operating_system.html.
There's a lacuna in the recursivity of Wirth's system: although he provides synthesizable source code for the processor (in Verilog, I think) there's no logic synthesis software in Oberon so that you can rebuild the FPGA configuration. Instead you have to use, IIRC, Xilinx's software, which won't even run under Oberon. Since then, though, Claire Wolf has written yosys, so the situation is improving on that front.
CP/M is interesting because it's close to being the smallest system where self-hosted development is bearable; the 8080 is just powerful enough that you can write a usable assembler and WYSIWYG text editor for it. But I don't think that makes it a good example to follow. We saw this weekend that Olof Kindgren's SeRV implementation of RISC-V can be squoze into 5900 transistors (in one-atom-thick molybdenum disulfide, no less) https://arstechnica.com/science/2025/04/researchers-build-a-... https://news.ycombinator.com/item?id=43621378 which is about equivalent to the 8080 and less than the Z80. And Graham Smecher's "Minimax" https://github.com/gsmecher/minimax is only two or three times the size of SeRV and over an order of magnitude faster.
There's no reason to repeat the mistakes Intel made in the 01970s today. We know how to do better!
CP/M, WordStar, and Turbo Pascal were/are pretty good though!
As you suggest, someone really should port an open source FPGA toolchain to Oberon to honor Prof. Wirth's great work.
- The command processor didn't have to be so limited, as amply demonstrated by ZCPR, or so hard to use, as demonstrated by the p-System.
- Record-oriented file access was probably a mistake. The 128-byte record size meant that you still had to use 2-byte record numbers to get files of over 32K, and that writing a single record required wastefully reading a whole 512-byte sector in order to not lose the other three records in the sector. Byte-based file access would have been far better for the usual case, even at the expense of needing 24-bit seek offsets for very large files (over 64K). This would have to be built on sector-based access, but the intermediate layer of record-based access is purely dead weight for most applications. Sector-based access (or access in larger blocks as in Forth) would allow you to use 1-byte sector numbers until the advent of double-density disks.
- Using different BIOS calls to write to the terminal, the printer, and the paper tape punch was obviously a mistake, and one that made it very difficult to extend the set of available devices. I believe HDOS did a better job here. Moreover, if you adopted byte-based file access, you could use a single BDOS call to write to a file, the terminal, the printer, or the punch, and analogously for reading. This also would have made it easier to support multiple terminals.
- The user interface of ED was stuck in the teletype era. But almost nobody ran CP/M on a teletype, because teletypes cost more than CP/M crates. Before long most CP/M machines had a monitor built in, like the Kaypro, Osborne, and H-89. Even BASIC-80's unusably bad line editor gave you a live display of the line you were editing, and WordStar demonstrated that it was possible to do much better on the same hardware.
- The "user" facility in its filesystem was useless.
So, I'm not a huge fan of CP/M. I think virtually all of its major design decisions were mistakes, except for the BIOS/BDOS split, though not such serious mistakes as to make it completely unusable. I'm interested to hear why you disagree so strongly.
The idea was that depending on the state of the IOByte the actual destination of "stuff" could vary.
Of course in the CP/M emulator I wrote/maintain I ignore that byte, because it turns out everybody else did too. (Kinda like user-numbers/areas, most people ignored them.)
"Pretty good" isn't the same as "perfect". All of your comments seem completely reasonable. But that BIOS/BDOS design made CP/M a minimum viable portable OS that enabled binary software portability and created an ecosystem across 8-bit hardware from many vendors (not to mention homebrew), starting in 1974. The closest things to it in that space were Microsoft BASIC (with many incompatible versions) and the UCSD p-System, as you note. So I rate CP/M "great" in terms of its industry innovation – specifically how it applied technology to develop a successful 8-bit PC compatibility standard, providing a model for the 16-bit era of DOS and IBM PC compatibles.
Years later, Linux seems to be stuck with multiple, incompatible formats for binary software packaging (snap, flatpak, appimage, docker, win32...) Though I guess you don't have to worry about different sizes of floppy disks.
https://heathkit.garlanger.com/diskformats/HDOS_Disk.pdf confirms: 256 bytes, 10 sectors, 40 tracks.
Paterson's article explains why he copied the FAT filesystem from Microsoft BASIC but extended the cluster numbers to 12 bits. He also has some pretty damning criticisms of both the CP/M filesystem design and its BIOS interface.
Many of the recent/modern emulation projects work the same way. In addition to RunCPM there's also the excellent rust-based iz-cpm project which I enjoyed studying at times.
Note that old software is likely to contain security flaws and other bugs, so isolation/sandboxing is important.
Thanks for the iz-cpm reference!