I got Scott Baker's 512K RAM/ROM board built, and started modifying z80ctrl to work with it. The first step was to modify the z80ctrl firmware to do outbound IO requests. I added io_in and io_out functions to bus.c, which do IO reads and writes directly from the AVR to other peripherals. I added in and out monitor commands that use these functions to read or write directly to a specific port. These commands can be used with any other hardware, not just the ROM/RAM board.
I also added a page command to the monitor that provides easy control over memory page registers on the RAM/ROM board without having to use the low-level I/O commands. The page command allows 4 different 16KB pages to be specified or just a single page. If only one page is specified, z80ctrl will assign banks 2-4 to the three contiguous pages immediately following the page specified for page 1. After a reset, the ROM/RAM board defaults to having paging disabled with all 4 banks pointed to the first 16KB or ROM. Pages 00-1f are ROM, and 20-3f are RAM, so in z80ctrl, running "page 20" switches to the first 64KB in RAM, and then programs can be loaded into RAM from SD card as usual.
One problem with this is that when z80ctrl resets the Z80 to run a program, the paging registers in the RAM/ROM board also get reset. To get around the problem, I store the last configured pages and automatically issue the I/O commands to reconfigure the paging registers to their previous values after a reset. Once the Z80 is running, it can control the paging registers directly.
Part of the intended design of the z80ctrl is that it doesn't really need a ROM at all since it can load programs into RAM from a file on the SD card. I initially tried to use 512KB RAM chips in both sockets; however, that doesn't work because three of the pins on the ROM (SST39SF040) chip are different than those on the RAM (AS6C4008). The pins are shuffled around as follows: A14 (RAM) -> A15 (ROM), A15 (RAM) -> WE# (ROM), WE# (RAM) -> A14 (ROM).
It should be possible to cut the traces to those three pins and run some wires to the correct pins so I can use RAM chips in both sockets. However, for now, I've decided against this. Instead, I'm planning to add a switch to the loadbin and loadhex commands that will let the ROM chip be flashed with an image directly from the SD card. The ROM chip doesn't write simply by asserting the WE# line; there is a special command sequence, so I will have to modify my memory load function to support that. I may eventually design my own board that contains two 512KB RAM chips instead of 1 ROM and 1 RAM.
So far, I've gotten altmon, scmon, and CP/M to run successfully with the z80ctrl and 512K RAM/ROM boards. I initially had a few bugs, but these have been found and squashed, and everything appears to be working now.
In my REV3 board, I addressed the hardware changes necessary to safely support bidirectional IORQ usage. To avoid unintentional hardware damage, these features are disabled by default on REV1/REV2 boards. You can override this safety on REV1/2 boards by adding -DOUTBOUND_IORQ to your CFLAGS in the Makefile. It's safe to use bi-directional IORQ as long as the z80ctrl IO block jumper is set to the rightmost position, which connects the AVR's IORQ pin directly to the IORQ bus line. However, if the IO address selection jumper is accidentally left in one of the other positions, the AVR IORQ pin will be connected directly to VCC or to one of the outputs of the 74HCT139, and one or both chips may be damaged.