Some time ago I found FabGL, which is a fantastic library implementing a VGA controller and a PS/2 keyboard controller for the ESP32. It means you can use Arduino IDE to create a sketch that talks directly to a real VGA display and a real PS/2 keyboard. For VGA, Red, Green and Blue signals and Hsync and Vsymc signals are handled by the library, the only thing you need to provide is a DAC made with three resistors (I chose the 8 color mode). The keyboard interface also requires a few resistors for handling CLOCK and DATA signals.
In my case, the main software running on the ESP32 sketch is a Z80 emulator. The emulator, in turn, runs my CZ80 Basic ROM, which I adapted from NASCOM Basic. The ROM is stored in a const array in memory for faster access.
This is how the setup() function initializes FabGL:
// PS/2 PS2Controller.begin(PS2Preset::KeyboardPort0); // VGA (GPIO 22 to Red, GPIO 21 to Green, GPIO 17 to Blue, GPIO 16 to HSync and GPIO 4 to VSync) DisplayController.begin(GPIO_NUM_22, GPIO_NUM_21, GPIO_NUM_17, GPIO_NUM_16, GPIO_NUM_4); DisplayController.setResolution(VGA_640x240_60Hz); // Terminal Terminal.begin(&DisplayController); Terminal.connectLocally(); Terminal.loadFont(&fabgl::FONT_8x8); Terminal.setBackgroundColor(Color::White); Terminal.setForegroundColor(Color::Black); Terminal.clear(); Terminal.enableCursor(true);
The machine also emulates two 250KB floppy disks and one 8MB hard disk. The first floppy image is read-only and also stored in flash memory (the ESP32 has lots of flash memory, so I could spare some). This image is bootable and contains a copy of CP/M 2.2 with a a few utilities. I chose the common CP/M floppy format using 77 tracks of 26 sectors each, but with no sector interleaving. The disk images are created with a simple tool written in C.
The second floppy image and the hard disk image are stored on a SD card and are writable. The emulator looks for files named disk1.dsk and hd.dsk on the SD card root and maps them during startup.
CP/M (BIOS, BDOS, CCP) was compiled from source. I used version 1.8 of this z80asm assembler. It is much smaller and much easier to setup than z88dk, but it uses a different syntax. I found the original Digital Research CP/M source code here. The other utilities distributed with CP/M were found here (in binary form).
The Basic interpreter was also compiled from source. It is a custom version I have been using for some years now and has its origins on the NASCOM Basic source listing. A similar version can be found here (but of course without my changes). I had to change the source code a lot because of the different syntax used by the assembler.
I am preparing a source code distribution of everything, but I am still unsure about some aspects of licensing, mainly because it uses code from Digital Research. There are alternative versions of CP/M that do not use code from DR, but I have not tested them yet.
For now, here is a picture of my test board (with copious amounts of hot glue, naturally):
I have selected to display black text over white background using a 8×8 bitmap font (as seen on the initialization code above). Picture quality is quite good (the white blob at the bottom is a defect of the monitor screen):
In this session, the computer starts at the Basic interpreter prompt. Then I ran the command “BOOT”, which loads the first sector of the first floppy drive into memory and jumps to it. The boot sector is the first stage of the CP/M boot process, which loads BDOS and then starts CCP. Once in CP/M, I typed a “DIR” command to show the contents of drive A.
This project shares a lot of ideas and code with the hardware implementation of my CZ80 computer. Here hardware is emulated by an ESP32 and the display uses VGA. The real CZ80 will run on actual Z80 and will use composite video for display, but the Basic interpreter is mostly the same (as you can see in the “CZ80 BASIC” prompt above).