This connector is interesting, as it connects directly to the bus, meaning all ROM access shows up here. There is no "enable" pin (nor high address pins) that can be used to tell whether the access is actually intended for the connected device (CD64 is in an appropriate mode and address is in the correct range). Pulling the data lines low will cause that bit to read 0, no matter what the address, so it will corrupt reads/writes to other sources, and blindly listening to these pins would also cause your device to respond to accesses intended for other things.
The only safe way to use this connector would be for your device to listen for a series of writes as an "enable" signal, and hope no game happens to trigger it by accident. Alternatively, patching into the high address lines on the cartridge bus would allow you to tell if the address is actually in the range reserved for this connector, but it wouldn't tell you the CD64 mode (unless you listened for those writes too), and different modes actually assign different ranges.
A remote possibility is that there's a way from software to control the +5VDC pins on this port, so the device isn't powered on until the system is ready. However I see no evidence to support this theory.
Pin 38 is interesting; it may have been intended to allow the device to access the third flash ROM when there is no other bus activity. Currently this chip stores Gameshark ("X-Terminator") codes, but it may have been intended for boot code or resources for the MPEG decoder that would have connected here.
The address pins keep their state after each access, while the data pins are at +3V whenever no access is occurring. I can't tell for sure with just a multimeter, but it looks like high=0 on the data lines, whereas high=1 on the address lines.
Since the bus is 16-bit, there is no A0 pin. Byte access returns only the high 8 bits; word access probably gets split into two halfword reads/writes.
The expansion connector is mapped to 0xB1xxxxxx (and sometimes 0xB0xxxxxx; see mode chart below). Beware that games' exception handlers will usually trigger and consider the game to have crashed if you perform any unaligned access.
I also dug up some other interesting information:
The disc read code is fussy about ROM size. If the ROM is not a multiple of some unknown size, it won't appear in the list. 13,107,200 bytes (12.5MB) works, 13,107,201 does not. Keep this in mind if you want to add on to the end of a ROM.
The CD64 enable register (0xB780000C) has an unknown quirk. Normally you write 0x0A to this address (as a word; the high 3 bytes are ignored) to enable the CD64 registers. Early versions of my test program did this immediately before setting the mode (0xB7800000) and the result was inconsistent behaviour, as if sometimes the mode wasn't changed. Setting it only once at the beginning of the program solved this problem. This could mean you must wait some time after enabling before using the registers, or that writing a second time disables it - obviously there needs to be some way to disable the registers before starting a game.
The third flash ROM, which currently stores Gameshark codes, is mapped to 0xB7000000. To read it, read a word and discard the high byte of each halfword, e.g.:
LUI $A0, 0xB700or:
LW $A1, xxxx($A0)
SLL $T0, $A1, 8
ANDI $T0, $T0, 0xFF00 ;first byte
ANDI $T1, $A1, 0xFF ;second byte
OR $A0, $T0, $T1
tmp = word[x]
byte1 = (tmp >> 16) & 0xFF
byte2 = tmp & 0xFF
data = (byte1 << 8) | byte2
The chip is an SST-29EE010 (128KB capacity). Writing would most likely follow the same method, placing a 16-bit payload in those two bytes. Accessing individual bytes (as halfwords) should also work the same.
The CD64 website documents some of the modes, but not all. The entire map appears to be:
|0||CD64 BIOS||Expansion port||Cartridge||DRAM (R/W)||CD64 BIOS||X-Terminator & I/O|
|1||CD64 BIOS||Expansion port||Cartridge||DRAM (R/W)||CD64 BIOS||X-Terminator & I/O|
|2||Expansion port||Cartridge||DRAM (R/W)||BIOS/Expansion port|
|3||Expansion port||Cartridge||DRAM (R/W)||BIOS/Expansion port|
|4||DRAM (read-only)||Expansion port||Cartridge||BIOS/Expansion port|
It's possible to switch out of any mode, but no modes allow writing beyond the first 32MB of DRAM, hence the ROM size limit. If I could find a 64MB module, it might be possible to defeat this limit by simply manually operating the write line and/or highest address line of the DRAM (which could then be connected to a pin on the expansion port and done automatically in software). Of course reprogramming the CPLD would be a better way, but having no method to do so (nor to even back it up) and no experience with CPLDs, I can't try this yet.
In mode 4 the 32MB DRAM is mirrored at B2 and B3, but this is probably because it's only 32MB; I suspect with a larger module all 64MB would be readable here.
In mode 5 (and 6) again the 32MB is mirrored across the entire range, but this would probably change if you installed a larger module. In theory up to 128MB is usable if you can write to it somehow.
Reading past the end of cartridge ROM or BIOS reads open bus; the result will be the low word of the address repeated for the entire word. Addresses above 0xB7xxxxxx are also open bus.
"BIOS/Expansion port" means the high 16 bits of each word will come from the expansion port and the low 16 will come from the BIOS. This isn't terribly useful since you can only read every other halfword of the BIOS (unaligned access throws an exception). 0xB7xxxxxx reads the X-Terminator chip instead of the BIOS (since BIOS is mapped to 0xB6xxxxxx and XT is mapped to 0xB7xxxxxx); in other words, in this range one halfword comes from the same place as it would in mode 0 and the other comes from the expansion port.
The parallel port adaptor (whose circuit diagram is on the CD64 website) contains some buffers and latches to make the port easier to use.
When you write a word to 0xB78xxx84 the low byte of that word is output to the data lines. They do not retain their state; when not being written, they read 0V (logical zero). For input, read a word from 0xB78xxx80; the state of the data lines is found in the low byte (+3VDC=1, 0V or disconnected=0). Thus, the adaptor adds latches to keep the last state written so the other end can read it without having to be in perfect lock-step (or having to run big slow loops).
There are still some things I want to try with this hardware. First I want to build this adaptor and dump the three flash ROMs. Then I'd like to play with the audio input port, look up documents and see if it has to be enabled in software or just given an input.
I'll also want to research how one goes about communicating with various IDE devices and see if I can interface with hard drives and CF cards, which will be the first step toward writing better software.
Finally I'd love to find a 64MB or even 128MB DRAM module I can install and see if I can get it to do anything interesting. I don't doubt I can work out some sort of hack for this.