I recently acquired a Kazzo, with hopes of linking it to an emulator to make a sort of CopyNES with the power of a full PC under the hood (or, put differently, an emulator with a real cartridge slot). With a PC underneath, I could log every read and dump-as-I-go, which should in principle work with any mapper, albeit the log is not a ROM file, and more care will be needed to get a *complete* dump. The actual software modifications required to make the emulator communicate with the Kazzo were pretty trivial, and I now have Mednafen and nesemu2 modifications (I'm on Linux) that, at least on the surface, appear to work correctly with Kazzo. They work with NROM, anyway
Unfortunately, the games I have—and the reason I was interested in this—are all weird pirate carts that have unusual copy protection. I literally own not one game that's not nonsense. In particular I'm using Shenzhen Nanjing's Final Fantasy VII as an example, because there's also a known-good dump, so I can test the behavior I'm getting off the Kazzo vs the dump. The copy protection used by these carts doesn't seem to be documented especially well...
I'm getting some progress, but I think I'm being foiled by copy protection, so I'm wondering if anybody with some familiarity with the copy protection either used by these pirate carts, or just cart copy protection in general, might have some tips.
With FF7, the behavior I'm getting via Kazzo mirrors the ROM for quite a while: It waits for a V-blank, copies some copy-protection/page-switching code into RAM at 0x400, runs that, successfully switches to the other page, switches to page 1, then sets up RAM including copying a whole jump table into 0x6800 (and the jump table is correct), all the while jumping back and forth between pages 3 and 0 from instructions in the standard PRG range, and finally copies another chunk of page-switching code to 0x400 and runs it. That page-switching code switches to page 0xe, which is where things go awry.
To be a bit more detailed, all the "copy protection" that it *appears* to do is writing a correct code to 0x5300, and a bit of in-PRG page swapping (which is trivial with the Kazzo).
The data I get off the cart when I switch to page 0xe is clearly junk, which is a bit disheartening since the start-up page (which is actually page 2), page 0, page 1 and page 3 all appear flawless. I've dumped the whole PRG region and compared it against the ROM for those pages, and they're perfect. I've tried a lot to see what might be wonky, but no luck.
Here are some things that I've tried:
I fear that things may be a bit dire. I'd appreciate any advice on whether any of the following is possible:
Otherwise, I'm just hoping that somebody goes "have you tried this extremely simple thing", I try it, and it just works
Unfortunately, the games I have—and the reason I was interested in this—are all weird pirate carts that have unusual copy protection. I literally own not one game that's not nonsense. In particular I'm using Shenzhen Nanjing's Final Fantasy VII as an example, because there's also a known-good dump, so I can test the behavior I'm getting off the Kazzo vs the dump. The copy protection used by these carts doesn't seem to be documented especially well...
I'm getting some progress, but I think I'm being foiled by copy protection, so I'm wondering if anybody with some familiarity with the copy protection either used by these pirate carts, or just cart copy protection in general, might have some tips.
With FF7, the behavior I'm getting via Kazzo mirrors the ROM for quite a while: It waits for a V-blank, copies some copy-protection/page-switching code into RAM at 0x400, runs that, successfully switches to the other page, switches to page 1, then sets up RAM including copying a whole jump table into 0x6800 (and the jump table is correct), all the while jumping back and forth between pages 3 and 0 from instructions in the standard PRG range, and finally copies another chunk of page-switching code to 0x400 and runs it. That page-switching code switches to page 0xe, which is where things go awry.
To be a bit more detailed, all the "copy protection" that it *appears* to do is writing a correct code to 0x5300, and a bit of in-PRG page swapping (which is trivial with the Kazzo).
The data I get off the cart when I switch to page 0xe is clearly junk, which is a bit disheartening since the start-up page (which is actually page 2), page 0, page 1 and page 3 all appear flawless. I've dumped the whole PRG region and compared it against the ROM for those pages, and they're perfect. I've tried a lot to see what might be wonky, but no luck.
Here are some things that I've tried:
- Normally I read from the cart in chunks of 0x100, the Kazzo's transfer size. Just in case the cart cares, I've also tried doing it one byte at a time. This technique is exceedingly slow, and gets the exact same result.
- Mednafen doesn't really claim to be cycle-accurate, which is why I tried nesemu2, complete with the one-byte reads mentioned above. In that case I did the same for the PPU, just in case it watches the PPU read timing w.r.t. the CPU read timing. No dice.
- In case the cart snoops on unrelated writes, I modified the Kazzo firmware to have a mode in which it claims to be reading (PRG-R/W set to R) but actually writes a specified value. In that mode I intercepted *every* memory read and write and sent them to the cart as appropriate, so it was kept apprised of every write to RAM, reads from 0x2---, etc. No change.
- I've tried ignoring what the real mapper-switching code does and writing a bunch of other values to the appropriate addresses—0x5000, 0x5100, 0x5200 and 0x5300—to see if I could find the page that I want squirreled away somewhere. The cart is definitely responding to those writes, and switches out the mapping, but none of them are correct.
- With a small firmware modification, I've checked whether anything appeared open-bus that shouldn't be, or have bus conflicts. Doesn't seem to be.
I fear that things may be a bit dire. I'd appreciate any advice on whether any of the following is possible:
- If the cart actually has a timing crystal in it, this whole technique is screwed. However, I've also written scripts to just do the cart behavior as fast as possible, and those yield exactly the same result.
- If the cart doesn't have a timing crystal, but counts Phi2 pulses, the firmware might need some *severe* modification. Kazzo doesn't particularly try to make sure that the number of Phi2 cycles actually matches what a Famicom would do.
- If the cart is watching the PPU addresses at the same time as the CPU addresses for anything suspicious, I'm properly screwed. The Kazzo commons the address pins since it only ever reads/writes one at a time. In fact, it commons the address pins to the data pins, with a latch so it can set the address then read the data. It's weird. I feel like the cart would have to specifically anticipate the Kazzo to use this fact for copy protection tho, and that seems unlikely.
Otherwise, I'm just hoping that somebody goes "have you tried this extremely simple thing", I try it, and it just works