Cromix is a multi-user, multi-tasking operating system – for the Z80!
It shocked me at the time that anyone would think of such a thing, much less attempt something so clearly far beyond the realms of possibility. It can’t be done because:
– the Z80 is a microprocessor not a minicomputer
– users need memory and the Z80 has a 64K ceiling
– programs typically (at the time) took about 32KB each
– it doesn’t have a supervisor mode
– it doesn’t support virtual memory
– and on
As you can see in the picture above, someone (Cromemco) went and did it anyway. It also worked, and worked well.
In some ways, cromix was linux before linux was invented. You see, unix was legally constrained so you couldn’t just port the software. There’s more on that on wikipedia under the background of linux so Linus Torvalds wrote his own from scratch. Cromix seems to have a similar background. Certainly it was the unix for Z80 of the time. But it wasn’t actually unix – it is similar, but not quite the same.
If you’ve used cromix before, using it again will be second nature. However, if you’re like me (always wanted to but couldn’t get my hands on it), you may find “close to but not unix” will trip you up in places. Here’s some hints:
– instead of cat (unix for CP/M type) or type (CP/M for unix cat), there’s “ty”
– instead of cd or chdir to change directory, there’s “d”
Other things work as expected: “ps” (example in the picture) for process status, “mount”, “umount”, “ls”, “ls -l”, even “l”.
There is a “/dev” directory, and “/etc” and “/bin”. There is an “/etc/passwd” file and so on. Close, but different. I really recommend getting a copy of the manual (pdf).
You can download a copy of z80sim with the necessary hardware configuration and a boot disk from cpm/z80sim/run-cromix1127.zip. (You can also run it in the ZEMU emulator by Wiley J Moore if you follow Marcus’ instructions running-cromemco-cromix-inside-z80.html). Mine’s easier to setup and run, but it isn’t yet as rock-solid as the ZEMU one.
On the way, there were a few lessons learnt.
“Unable to open console”
This was surprising because it was displayed on the console. An internet search turned up one other person who had the problem and some people who remembered having seen it before (on a real system probably) but couldn’t remember the solution. It turned out (after tracing through the code), that cromix was checking bit D2 of IO port 00, the console/UART status register. This bit is supposed to be high if the UART is connected to a serial terminal. None of the CP/M or CDOS versions I’ve seen check that; but cromix did. The solution for me was to modify the emulator to report this bit as high. Of interest, I suspect that Udo probably already has, or had, z80sim working with cromix – at least in a unix environment. His cromemcosim files had an equivalent line doing the same.
“Not supported bank select”
This was one of those “it will never occur” messages. It was in the 256KZ software I added a little while back. It happens when you select a memory bank that doesn’t exist. Cromix happily works its way through all of the memory banks, even those that don’t exist. If you read the fine print on the memory card manuals (normal print really), you are supposed to change switch settings to make bank 0 appear in the missing slots. My fault and easily fixed. I’ve changed the 256KZ software to select bank 0 for unused slots. If you’re copying the (later) software, you can change a “#define” to include more than 4 x 64K on a 256KZ card and the software will adjust the “built-in / virtual” switch settings for you. There isn’t a runtime switch selection.
“Cannot initialize STDC controller”
Marcus’ “Load Cromemco RDOS (Resident Disk Operating System) monitor, version 03.12” line seems pretty routine; but it is not. If you’re not careful you’ll try and boot a non-existent hard disk. RDOS changed over the years from “b” to boot (drive A) to “b” to boot the drive set by the “unused” DIP switches on the 16FDC card, to boot from hard disk. His picture in the article shows “bb” to boot from disk B. “ba” is the RDOS0312 equivalent of the earlier “b”. However there’s more to this than meets the eye …
Invalid Opcode at … or Hanging
These are both indicative of interrupt driven systems going awry. However, it wasn’t that at all. Marcus’ comment to use RDOS was either a happy coincidence for him or the result of what would have been a few frustrating hours. It turns out that the boot sector in cromix assumes a few things. That’s strange for a boot sector as it is normally the first step of loading an operating system. If you disassemble the boot sector, you’ll find it skips a few steps if the CY flag is set. It looks like this allows RDOS (for example) to override the normal boot device, eg boot from drive A and then load the rest from drive B (or H etc). If you get the wrong combination of CY and data in A’, you’ll load nothing and run random memory.
Marcus’ solution, or unsuspecting luck, was to run RDOS first. That sets CY and A’.
I wanted to be able to boot immediately so I typically copy the boot sector to a hex file and then start the simulator with that. After patching out the “JR C,…” instruction and recalculating the hex format checksum (twice, I was doing it by hand and got it wrong the first time), it booted reliably every time. I really thought I’d solved all of the instability issues at that point as it ran flawlessly enough from that point for me to package and release it (over 20 more tests). But there is still something else to find and fix, sorry. (It seems more temperamental after I started closing down windows processes so perhaps it is load / timing related).
Running CP/M Under Cromix
There is evidence to suggest that this is possible. One of the programs on the Cromix disk is “debug.com” – a CDOS program. The cromix ones end in “.bin”.
If you run debug you get the familiar CDOS debug prompt:
# # debug DEBUG version 00.17 -
There is nothing at 0100H, but there is at 0000H:
-d 0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -d0 0000 C3 03 E9 FF FF C3 00 C7 C3 F5 FD FF FF FF FF FF C.i..C.GCu}..... 0010 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 0020 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 0030 A8 EB 17 FF FF FF FF FF C3 0A FE FF FF FF FF FF (k......C.~..... 0040 01 00 ED FB 00 00 00 00 00 00 00 00 00 00 00 00 ..m{............ 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 20 20 20 ............. 0060 20 20 20 20 20 20 20 20 00 00 00 00 00 20 20 20 ..... 0070 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 ........ -
Those are jump vectors into the BIOS at 0000H and into CP/M or CDOS (probably into the CDOS emulator) at 0005H. Looking into the BIOS gives:
-le900 E900 JP E92D E903 JP E934 E906 JP EDEB E909 JP EDFE E90C JP EE28 E90F JP E937 E912 JP E942 E915 JP E94D E918 JP E92D E91B JP E92D E91E JP E92D E921 JP E92D E924 JP E92D E927 JP E92D E92A JP E92D E92D LD HL,E955 -l E930 LD B,02 E932 JSYS 1B E934 JP EE2C E937 PUSH BC E938 PUSH DE E939 LD E,C E93A LD C,05 E93C CALL EA91 E93F POP DE E940 POP BC E941 RET
That is clearly a BIOS jump table. I also especially liked the “JSYS 1B” opcode. Here is a debugger that understands cromix system calls. In a less knowledgeable disassembler, that will be “RST 8” followed by a seemingly random instruction. It is always a single byte but other disassemblers will get lost if it looks like the start of a two or three byte opcode. I’ve been there.
JSYS 1B is “.printf”. The message at E955 says “Unimplemented CPM jump at address %04.4xH\r\n\0”. They’re not all unimplemented.
This is part of the CP/M topic.
Udo did get cromix running in z80sim for Mac. There’s a video at https://www.youtube.com/watch?v=YIirQYJK52U
Don’t try to login three users with my Windows version – it doesn’t have the telnet / networking stuff in Ver 0.08.
Correct, the UART status must be set if a terminal is connected, I needed a while too for figuring out what the Cromemco tty drivers are doing. For telnet consoles it is important to set the flag if a telnet connects, and reset the flag if it disconnects, else the getty processes will consume CPU time instead of going to sleep.
Cromix provides a CDOS call interface sim.bin, so many CP/M programs will run. Then there is a CP/M emulation program sim22.com that provides a somewhat better CP/M call interface. Markus has the program and PDF manual and it’s installed on the z80pack cromix_work disk in /bin.
Telnet consoles also aren’t working under Windows with the Cygwin z80pack machine. The problem is that Windows for some reason doesn’t generate signal SIGIO when a BSD socket connects. One would have to implement polling to check the sockets for incoming connections to accept them, and that is very nasty. The z80pack cpmsim machine supports SIGIO interrupt handling as well as polling for the sockets. For example MP/M works with multiple telnet terminals on Windows, but if you look at the source, oh my. I think I’ll just wait until Microsoft implements better BSD sockets.