It’s time to stop talkin' and start walkin' …
Disk initialisation
As mentioned in the previous article, the last step is about getting the virtual disk in flash formatted and set up correctly.
But instead of uploading all the disk blocks manually (and figuring out where exactly), I’m going to let the emulator itself do the work. So the plan is to embed the contents of the system track as data inside the emulator app, and then if flash memory does not yet have a valid disk image, to initialise flash and copy the data. Here is the corresponding code:
ie (disk.valid())
disk.init();
else {
disk.init(true);
// write boot loader and system to tracks 0..1
int pos = 0;
for (uint32_t off = 0; off < sizeof rom; off += 128)
disk.writeSector(pos++, rom + off);
// write 16 empty directory sectors to track 2
uint8_t buf [128];
memset(buf, 0xE5, sizeof buf);
for (int i = 0; i < 16; ++i)
disk.writeSector(26*2 + i, buf);
}
Creating an image for the system tracks is relatively easy. Assuming all the Z80 code has been assembled properly (I used z80asm, which works on MacOS and Linux), then we’ll end up with a couple of data files. For convenience, they are also in the code repository:
- boot.com is the 128-byte boot loader (source)
- bdos22.com is the core of CP/M 2.2 (source)
- bios.com is our 512-byte custom BIOS (source)
These three binaries need to be turned into a C header file and stored as data
inside the emulator. The trick is to first convert the binary data to a C data
definition, using xxd
:
cd code-z80
cat boot.com bdos22.com bios.com | xxd -i >../common-z80/rom-cpm.h
… and then include that file as const
data (i.e. in flash) in the emulator
with these lines:
const uint8_t rom [] = {
#include "rom-cpm.h"
};
That’s it. All the pieces have been worked out (I spent a lot of time testing it all, of course). The complete project for this “CP/M on F407” implementation can be found here.
The first power-up
Let’s connect the board, fire up the terminal emulator for access to the serial
console, and upload the system to the Black F407 board (using pio run -t upload
, as always).
Drum roll … here’s what appears on the serial console:
initialising internal flash
[JeeLabs Retro Z80]
64K CP/M Version 2.2
A>
Yeay - we have launched CP/M, running on a virtual Z80 inside a 32-bit ARM F407 µC!
In case you’re wondering:
- the first line comes from the
disk.init(true);
call insrc/main.cpp
- the second line comes from Z80 code in the boot loader, so system calls work
- the third line is the BIOS’s cold boot startup message
- the last line is the famous command prompt, which survived all the way to MS-DOS
And as everyone over a certain age knows: when you see “A>”, you type “dir”, of course!
A>dir
No file
A>
Haha. There’s obviously not much to see, since we don’t have any files or programs yet. Still, here’s a quick check that CP/M files work, using some of its built-in commands:
A>save 10 blah.dat
A>dir
A: BLAH DAT
A>era blah.*
A>dir
No file
A>
References
- The complete project for this “CP/M on F407” implementation can be found here.