So on the Discord, I've seen it stated here and there that the MMC1 serial interface inherently results in it being more difficult to perform bankswitches that can be safely interrupted and returned to without corrupting the mapper state. One suggestion I saw was to perform a check after each of the serial writes to ensure that an interrupt did not occur, and if one did, then reset the mapper and try again. However, I believe to have come up with a thread-safe bankswitching function that requires zero extra checks and is nearly as fast as what you would write if your interrupt handlers don't do any bankswitching:
And then, in any interrupt handler that does PRG bankswitching:The most crucial thing here is that we guarantee after an interrupt returns:
The only caveat with this approach as far as I can tell is that the resetting makes this only work if the game is written to keep the fixed bank in the 2nd window.
I thought this would be helpful to anyone writing a MMC1 game, and I am also very curious to hear if anybody sees issues or improvements to this technique.
Cheers!
[edit: added pha/pla for cur_prg_bank in interrupt handler]
Code:
;;; Arguments:;;; A: New bank valueset_prg_bank: STA cur_prg_bank INC * ; reset mapper STA $E000 LSR A STA $E000 LSR A STA $E000 LSR A STA $E000 LSR A STA $E000 RTS
Code:
interrupt_handler: <save registers> LDA cur_prg_bank PHA <do interrupt stuff> ;;; cleanup PLA JSR set_prg_bank INC * ; reset mapper <restore registers> RTI
- The currently loaded prg bank is cur_prg_bank as set before the interrupt
- The mapper is reset.
- If the interrupt occurs immediately after the mapper reset instruction, then the interrupt handler returns in a reset state, and the bankswitch function proceeds to do 5 serial writes like normal. This will just set the current PRG bank to cur_prg_bank again, which is fine.
- If the interrupt occurs after any of the serial writes, then the handler returns with cur_prg_bank swapped in, the mapper reset, and then the bankswitch function continues to do <=4 serial writes. Since 5 writes aren't performed, these serial writes do nothing, and the function returns with cur_prg_bank swapped in from the interrupt handler. The "leftover writes" are fine because when another bankswitch happens, the first thing it does is reset the mapper again.
The only caveat with this approach as far as I can tell is that the resetting makes this only work if the game is written to keep the fixed bank in the 2nd window.
I thought this would be helpful to anyone writing a MMC1 game, and I am also very curious to hear if anybody sees issues or improvements to this technique.
Cheers!
[edit: added pha/pla for cur_prg_bank in interrupt handler]
Statistics: Posted by foobles — Fri Oct 11, 2024 9:49 pm — Replies 4 — Views 208