Super Robot Wars 4 is a Mode 21 ("HiROM") cartridge, but executes code exclusively out of "LoROM" banks ($80 and up). Each of the first several 64K banks contains 65816 machine code in its upper half and graphics data in its lower half. The remaining banks contain nothing but data (which is accessed via the standard HiROM banks, $C0 and up)
Any one know other SNES games that use this design? It's a clever way of reusing code that was originally written for Mode 20 and expects to access ROM, RAM and MMIO using 16-bit absolute addressing without switching banks (I suspect SRW4 reuses much of the engine code from SRW3 and SRW EX, both Mode 20)
Kirby Super Star and Kirby's Dream Land 3 both seem to mix-and-match the LoROM and HiROM banks pretty heavily (from both the CPU and the SA-1), though I don't know if those count, since SA-1 games are kind of more like a hybrid between the two anyway.
Doom seems to keep almost all of its SuperFX code in bank 00 (and SuperFX data in 00-3F) while running most CPU-side code out of 40+ (except for when the CPU is running in RAM, which is a lot of the time).
I know for sure that I've seen (and commented on) some non-coprocessor Mode 21 games that heavily use 00-3F (or 80-BF), but I don't remember what they are anymore.
Code in $8000-$FFFF, data in $0000-$7FFF?
I just assumed that most HiROM games up to 32 Mbit would probably work that way. It's certainly what I do (I decided early on that HiROM was "better", and once I'd figured out how it actually worked I just kept using it). I just don't understand why you would ever run code from a HiROM bank when you could do this instead. Is saving a few JMLs really worth losing absolute MMIO and RAM access? Or is there another tradeoff I'm missing?
93143 wrote:
Code in $8000-$FFFF, data in $0000-$7FFF?
I just assumed that most HiROM games up to 32 Mbit would probably work that way. It's certainly what I do (I decided early on that HiROM was "better", and once I'd figured out how it actually worked I just kept using it). I just don't understand why you would ever run code from a HiROM bank when you could do this instead. Is saving a few JMLs really worth losing absolute MMIO and RAM access? Or is there another tradeoff I'm missing?
You don't have to set the data bank equal to the program bank; in fact, there's no good reason to. When I see a lot of
phk; plb in 65816 code, to me it's a sign of thinking like a 6502 programmer. It's more efficient to keep code with code and data with data. Ideally all your little bits and pieces of const data (LUTs for binary-decimal conversion, etc.) will fit into one 32K bank (a LoROM mirror bank if you're using HiROM) and you can keep the data bank there all the time except when working with bulk data.
...right. I forgot about that.
I once wrote a renderer that ran out of FastROM with the data bank in WRAM, but other than that my codes are typically small enough that everything other than bulk data (and sometimes even that) fits in one bank. So I haven't had to think about this sort of thing much yet...
When decompressing graphics, level data, etc., the usual way is to set the data bank to RAM (7E or 7F), access the ROM through a far pointer (lda [srcptr],y), and the RAM through an absolute indexed address (sta dstbuffer, x) Indexed addressing can cross banks on the 65816, so in Mode 21 your compressed data can straddle banks freely (that's one of its two main advantages, the other being 64KB program banks)
ETA: Here's something clever SRW4 does: A large proportion of the 65816 code in the ROM is a bytecode interpreter; all the actual game logic appears to be written in bytecode. The bytecode interpreter contains hundreds of jumps to a handful of re-entry point addresses ("fetch next bytecode", "wait for vblank then fetch next bytecode", etc.) To save one byte per jump, rather than absolute jmls, the re-entry jumps are indirect jmls through a set of vectors in the first ROM bank, which is mirrored in bank 00.