ok, someone sent me his cartridge so i could mess with it and i have been able to have the cartridge extra hardware reverse-engineered (maybe not 100% completely but still more than needed to emulate the protection !)
i have been using a SGC explorer, which is a very nice teensy-based MD cartridge board interface build by Bruno Freitas, who was kind enough to offer me one a few month ago
http://www.brunofreitas.com/node/42
the cool thing with this board is that it can manage all necessary signals of the cartridge connector and you can reproduce the same access as the game is doing
after MANY hours of register poking, investigations and guess work, here is a summary of my notes
--------------------------
Memory Map (cartrige area)
--------------------------
$000000-$07ffff: lower 512KB ROM
$080000-$0fffff: mirror of $000000-$07ffff (VA19 not connected)
$100000-$5fffff: not mapped
$600000-$67ffff: internal hardware (see below)
$680000-$6fffff: mirror of $600000-$67ffff (VA19 not connected)
$700000-$7fffff: not mapped
-----------------
Internal Hardware
-----------------
(read)
~~~~~~
$600000-$60ffff: upper 512KB ROM selected bank (8 x 64K banks)
$610000-$61ffff: upper 512KB ROM selected bank (8 x 64K banks)
$620000-$62ffff: return alternate 4K chunks of $ff and $00 (fixed to last ROM bank ?)
$630000-$63ffff: mirror of $620000-$62ffff
$640000: not mapped
$640001: always return $00
$640002-$65ffff: mirror of $640000-$640001
$660000: not mapped
$660001: DATA1 register, see notes below
$660002: not mapped
$660003: DATA1 register + 1
$660004: not mapped
$660005: DATA2 register, see notes below
$660006: not mapped
$660007: DATA2 register + 1
$660008: not mapped
$660009: DATA3 register, see notes below
$66000a: not mapped
$66000b: DATA3 register + 1
$66000c: not mapped
$66000d: DATA3 register + 2
$66000e: not mapped
$66000f: DATA3 register + 3
$660010-$66ffff: mirror of $660000-$66000f
$670000: not mapped
$670001: see notes below (1)
$670002: not mapped
$670003: return same value as $670001 anded with 0x7f
$670004-$67ffff: mirror of $670000-$670003
(write)
~~~~~~~
$600000: n.a (!UWR not connected)
$600001: CTRL1 register (see below)
$600002: n.a (!UWR not connected)
$600003: DATA4 register, see notes below (2)
$600004-$60ffff: mirror of $600000-$600003
$610000: n.a (!UWR not connected)
$610001: n.a ?
$610002: not mapped (!UWR not connected)
$610003: CTRL2 register (see below)
$610004-$61ffff: mirror of $610000-$610003
$620000-$63ffff: n.a ?
$640000: n.a (!UWR not connected)
$640001: DATA5 register
$640002: n.a (!UWR not connected)
$640003: DATA6 register
$640004-$64ffff: mirror of $640000-$640003
$650000-$65ffff: n.a ?
$660000: n.a (!UWR not connected)
$660001: ??? (usually set to $00 after writing to $670001, sometimes set to the same value as $670001 ?)
$660002-$66ffff: n.a ?
$670000: n.a (!UWR not connected)
$670001: CTRL3 register (see below)
$670002: n.a (!UWR not connected)
$670003: n.a ?
$670004-$67ffff: mirror of $670000-$670003
CTRL1 register ($600001):
~~~~~~~~~~~~~~~~~~~~~~~~~
D7-D3: n.a ?
D2-D0: DATA4 write mode, see notes below (2)
CTRL2 register ($610003):
~~~~~~~~~~~~~~~~~~~~~~~~~
D7: enable (resp. disable) $600000-$6fffff ROM bank-switching & $670001-$670003 output when set (resp. cleared)
D6-D0: n.a ?
CTRL3 register ($670001):
~~~~~~~~~~~~~~~~~~~~~~~~~
D7: enable (resp. disable) DATA1/DATA3 registers update on $670001 reads when set (resp. cleared)
D6: select $670001 output mode, see notes below (1)
D5: select DATA register being updated on $670001 reads when bit7 is set (0: DATA1, 1: DATA3)
D4-D2: select upper 512K ROM bank (8x64K banks) mapped to $600000-$60ffff when CTRL2 bit7 is set
D1-D0: n.a ?
NOTES:
~~~~~~
(1) reading $670001 returns:
- $00 if CTRL2 bit7 is cleared
- DATA5 & DATA6 if CTRL2 bit7 is set and CTRL3 bit6 is set
- DATA5 ^ 0xFF if CTRL2 bit7 is set and CTRL3 bit6 is cleared
when CTRL3 bit7 is set, reading $670001 updates the value in:
- DATA1 if CTRL3 bit5 is cleared: DATA1 = ((DATA5 << 1) ^ DATA4) & 0xfe
- DATA3 if CTRL3 bit5 is set: DATA3 = (DATA6 << 2) & 0xfc
(2) writing $600003 updates:
- DATA4 register: DATA4 = data
- DATA1 register if write mode (CTRL1 bits 0-2) is set to $0: DATA1 = ((DATA5 << 1) ^ data) & 0xfe
- DATA2 register if write mode (CTRL1 bits 0-2) is set to $1: DATA2 = data & 0xfe
- upper 512K ROM bank (8x64K banks, using D2-D4) mapped to $610000-$61ffff if write mode (CTRL1 bits 0-2) is set to $7
- no effect (?) if write mode is set to $2,$3,$4,$5,$6 (game sometimes sets write mode to $6 and writes $00 or $01 to $600003)
(3) random quirks:
- writing DATA5 or DATA6 registers does NOT immediately change the value returned in DATA1 or DATA3 when proper CTRL3 bits are set, the change is only effective after reading $670001
- similarely, when mode=$0, any writes to DATA4 register immediately change the value returned in DATA1 but calculation will not use the last value written in DATA5 unless $670001 was read in between
- setting CTRL3 bit7 seems to immediately update the value returned in DATA1/DATA3 if DATA4/DATA5 was changed but switching CTRL3 bit5 will not take effect until next write to DATA4/DATA5 followed by $670001 read
- internal registers might be non-volatile, previous state seems to be restored on power-on
As you can see, it seems the ROM is actually 1MB but i noticed similar 4 kB (or so) chunks of $ff and $00 in the various 64k bank that can be accessed through $600000-$60ffff and $610000-$61ffff as in the lower 512KB, so i suspect the initial ROM was initially 512kB then expanded to 1MB by copying out some chunks of data to upper 512kB. Also notice how VA19 is disconnected on the cartridge port, to ensure the upper area can not be directly accessed.
There is no public ROM available as i promised it to the cartridge owner and it' s up to him to decide when he wants to release it (I think he wants to get it fixed first). Indeed, it doesn't work with any existing emulator (except genesis plus gx) anyway and would probably be kind of hard (but not impossible I guess) to patch copy protection and bank-switching. All the infos are there though...