Hi all, I thought I'd share my progress seeing what's possible with a Raspberry Pi Pico connected to a RC2014 system.
I started off having the Pico acting as an I/O device with the eventual goal of having it act as storage for the RC2014. I then went off on a tangent and I now have the Pico replacing the Pagable ROM module and the 64k RAM module in my RC2014 Pro system.
The PIO engine in the Pico deals with the low level interaction on the bus while the ARM CPU maintains an array that acts as the RAM/ROM.
I declare an array as follows:
uint8_t mem [65536] = {
0xc3, 0xbd, 0x00, 0x18, 0x0f, 0xc3, 0x64, 0x05, 0xc3, 0x03, 0xfe, 0x00, 0xc3, 0xbd, 0x00, 0x00,
0xc3, 0x06, 0xfe, 0x00, 0xc3, 0x4b, 0x01, 0x00, 0xc3, 0x09, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
....
I've converted the contents of SCMonitor-v100-R4-RC2014-16k-ROM.hex to populate the array above.
After some initialisation, the main loop looks like:
uint bits;
uint addr;
uint8_t data;
uint status;
while(true) {
/*
bits == 0xAAAADDSS
AAAA == 16 bit address
DD == 8 bit data (0x00 during a z80 READ)
SS == 8 bit status
0x00 => z80 READ
0xff => z80 WRITE
0x7f => z80 REFRESH
*/
bits = pio_sm_get_blocking(pio, sm);
addr = bits >> 16;
status = bits & 0xff;
if (status == 0) {
pio_sm_put_blocking(pio, sm, mem[addr]);
}
else if (status == 0xff) {
data = (bits >> 8) & 0xff;
mem[addr] = data;
}
else if (status == 0x7f) {
// refresh, do nothing
}
else {
// error?
}
}
SCMonitor works nicely and I'm able to boot CP/M despite not implementing paging yet as the whole memory is writable so CP/M just writes over the top of the ROM values.
The PIO engine uses the WAIT line as there is lots of scope for the Pico to block while exchanging data. For z80 writes the WAIT line is only held low for ~8ns so has no impact on performance. For z80 reads where the PIO engine has to pass the address up to the CPU and wait for a response the WAIT line is held low for ~170ns which is enough to add one clock cycle to all read operations.
I've tried over clocking the Pico (125Mhz -> 250Mhz) but that doesn't shorten the WAIT signal enough to avoid a delay on reads. There's probably some scope to tune the code.
I've learnt a whole lot getting to this point, but it's not clear if this is actually useful :)
Some thoughts about uses:
1. Debugging - You can add printf statements to the main loop and watch the code execute. The caveat being that the printf statements add a lot of delay.
2. ROM development - I've not burnt a ROM, but it may be faster to update a Pico than burn a ROM during development and testing.
3. Memory mapped I/O device.
Having the Pico act as a memory mapped I/O device is the area that I want to play with next. My first idea is to understand the USB function on the Pico so it can be connected to a PC. Then it may be possible replace xmodem for easier file copies, or streaming data directly to the PC so the PC can act as a display for the system.
My second idea is to try and combine the VGA output that is possible with the Pico with memory mapped I/O to essentially build a VGA adaptor. I've used most of the pins for the connection to the bus, but I think there are enough left over to generate a monochome signal if the same output is fed to each of R, G, and B. It's not clear if there are enough PIO resources left for this to work.
Is this is interest or use to anyone else?
And lastly, the obligatory picture of the board :)
Dylan