This patch converts MM2/RM2 to use the MMC3 mapper, allowing both larger ROMs (up to 512 KB PRG-ROM) and 2 switchable 8-KB banks, offering much greater flexibility for derivative hacks. Additionally, while this patch is primarily intended for hackers making their own MM2 hacks, it does slightly reduce lag, reducing CPU usage in the base game by about 0.6%, as well as fix the delay-scroll bug.
There were several motivations to create yet another MM2 MMC3 conversion.
1. Poor optimization. The previous MMC3 conversion adds an additional +25 cycles to each bank switch. While this doesn't sound like much, bank switches are observed to occur up to 25 times per frame (1500 per second). 25x25 cycles/frame add up to over 2% of the CPU, which directly increases lag. In contrast, this patch is actually slightly faster than the original game (-7 cycles per bank switch).
2. The previous conversion's banking implementation is not preemption-safe. That is, it is not safe to use 8 KB banks outside the NMI because the NMI handler reverts to 16 KB banking each frame. This patch provides preemption-safe bank-switching APIs for use outside the NMI.
3. This patch inherently fixes the delay-scroll bug present in the original game and the previous conversion.
Patches for both Mega Man 2 and Rockman 2 are included.
Mega Man 2 MMC3 Patch
v1.0
By Justin Olbrantz (Quantam)
This patch converts MM2/RM2 to use the MMC3 mapper, allowing both larger ROMs (up to 512 KB PRG-ROM) and 2 switchable 8-KB banks, offering much greater flexibility for derivative hacks. Additionally, while this patch is primarily intended for hackers making their own MM2 hacks, it does slightly reduce lag, reducing CPU usage in the base game by about 0.6%, as well as fix the delay-scroll bug.
MMC3 represents the sweet spot for mappers in NES hacks. While there are much more powerful mappers such as MMC5 and N163, support for these mappers varies considerably and they are poorly supported in flash carts, not to mention that NES outside Japan lack the cartridge connectors for expansion audio. As such, MMC3 is the most powerful mapper that is widely and well supported.
Patches for both Mega Man 2 and Rockman 2 are included.
Mega Man 2 (USA):
PRG-ROM CRC32 0FCFC04D / MD5 0527A0EE512F69E08B8DB6DC97964632
File CRC32 5E268761 / MD5 8E4BC5B03FFBD4EF91400E92E50DD294
File CRC32 80E08660 / MD5 302761A666AC89C21F185052D02127D3
File CRC32 A9BD44BC / MD5 CAAEB9EE3B52839DE261FD16F93103E6
Rockman 2:
PRG-ROM CRC32 6150517C / MD5 770D55A19AE91DCAA9560D6AA7321737
File CRC32 30B91650 / MD5 055FB8DC626FB1FBADC0A193010A3E3F
Others with the same PRG-ROM checksums will likely work just as well.
WHY ANOTHER ONE?
There were several motivations to create yet another MM2 MMC3 conversion.
1. Poor optimization. The previous MMC3 conversion adds an additional +25 cycles to each bank switch. While this doesn't sound like much, bank switches are observed to occur up to 25 times per frame (1500 per second). 25x25 cycles/frame add up to over 2% of the CPU, which directly increases lag. In contrast, this patch is actually slightly faster than the original game (-7 cycles per bank switch).
2. The previous conversion's banking implementation is not preemption-safe. That is, it is not safe to use 8 KB banks outside the NMI because the NMI handler reverts to 16 KB banking each frame. This patch provides preemption-safe bank-switching APIs for use outside the NMI.
3. This patch inherently fixes the delay-scroll bug present in the original game and the previous conversion.
HOW TO USE IT
To attempt to make this patch as user-friendly as possible, APIs and ca65 includes are included for bank-switching: mm2mmc3.inc for Mega Man 2 and rm2mmc3.inc for Rockman 2.
Two series of functions are provided: the ordinary (safe) functions, and unsafe functions. Here these refer to whether the functions are preemption-safe and may be used outside the NMI. Additionally, bank-switches made using the unsafe functions in the NMI handler are not persistent and will be reverted at the end of the handler; this is usually exactly what is intended by bank switches within the NMI.
Switch16kBank
Persistently switch the entire $8000-bfff region to the 16 KB bank specified in A.
SwitchBank8
SwitchBankA
Persistently switch the $8000-9fff and $a000-bfff regions, respectively, to the 8 KB bank specified in A. Note that the bank number for SwitchBank8 MUST be even.
Switch16kBankUnsafe *
SwitchBank8Unsafe
SwitchBankAUnsafe
These functions mirror the safe versions but do not set the current bank variables and thus are not safe to use outside the NMI as they will be reverted at the end of the NMI handler. This also means that it is not necessary to revert changes in the NMI manually.
* Switch16kBankUnsafe clobbers X.
Cur16kBank
This variable is used by the original game to track what 16 KB bank is currently selected by the game loop so it can be restored by the NMI handler. It is automatically set by the safe switch functions, and in general only need be accessed directly in 1 scenario: when a custom function manipulates the banks and needs to restore the banks the game loop expects before returning. In this case, save the value of Cur16kBank before performing bank-switching and call Switch16kBank with it before returning to the game loop.
The IRQ
The MMC3 chip contains a scanline counter that can be used by derivative hacks. But even if it is not, the banking APIs of this patch require some extra work to be used in any hack in which the game loop, IRQ handler, and NMI handler all perform bank switches (no special treatment is required if the IRQ is not used or its handler does not perform bank switches).
As the IRQ handler may be preempted by the NMI, the safe versions of bank-switching functions must be used in the IRQ handler. However, these functions may already be in use by the game loop, so the banking state must be saved by the IRQ handler before modification and restored afterward. To avoid consuming precious common bank space with functions that will not even be used in many hacks, these functions are provided as macros rather than being a part of the patch itself.
That said, use of bank-switching in the IRQ is complex and there is no one-size-fits-all solution that doesn't add significant overhead unnecessary for most hacks. The save/restore macros below will satisfy the use case that the game loop, IRQ handler, and NMI handler all switch banks but only the NMI can interrupt the IRQ handler. If the NMI handler enables interrupts and can be interrupted by the IRQ, you will have to roll your own solution.
save_irq_bank_regs
Save the banking state at the start of the IRQ handler to the stack so that banking can be safely performed in the handler. Clobbers A.
restore_irq_bank_regs
Restore the banking state from the stack at the end of the IRQ handler after all bank-switching has completed, before return from interrupt. Clobbers A.
COMPATIBILITY
mm2mmc3 frees up the following previously used range of file offsets:
3804f-38060 (12)
As well, mm2mmc3 substantially modifies the following ranges:
38038-3804e
38061-38066
3c010-3c060
3d09d-3d0e6 (US) / 3d09a-3d0e3 (J)
Additionally, to free up space mm2mmc3 eliminates the SetMmc1Ctrl function used to set the screen mirroring mode. Instead, hacks should directly set the mirror register MirrorReg to either MIRROR_VERTICAL or MIRROR_HORIZONTAL, should they need to change the mirroring mode.
Mega Man 2 (USA):
PRG-ROM CRC32 0FCFC04D / MD5 0527A0EE512F69E08B8DB6DC97964632
File CRC32 5E268761 / MD5 8E4BC5B03FFBD4EF91400E92E50DD294
File CRC32 80E08660 / MD5 302761A666AC89C21F185052D02127D3
File CRC32 A9BD44BC / MD5 CAAEB9EE3B52839DE261FD16F93103E6
-
Rockman 2:
PRG-ROM CRC32 6150517C / MD5 770D55A19AE91DCAA9560D6AA7321737
File CRC32 30B91650 / MD5 055FB8DC626FB1FBADC0A193010A3E3F