As the problem of writing to mappers can be somewhat a pain for some people arround, as an interrupts can cause a mapper write procedure to be interupted, and then the interrupt would want to write to the mapper on its own, making the write of the main programm fail.
Disabling interupt can be a solution, but this will delay the interupt and in some case you want to avoid this. I guess I'll post some code that will allow solutions to fix this. Those allow all interupt and main code to do any mapper write all the time, if used proprely. Of course any personal variant of those will work.
MMC1 writes needs only 2 zero-page variables, while MMC3 needs only one zero-page variable.
MMC1 : Main programm MMC1 write routine. Enter with A=Data to write and Y=High byte to adress you'd want to write to ($80-$9f for reg0, $a0-$bf for reg1, etc...). X is unnafected.
MMC1 : Code to write to the MMC1 in Reset, IRQ and/or NMI code (enter with A=Data to write). I use a fixed adress for faster performance, but it's also possible to implement it the fashion as it's above. You'd typically make as many copies of it as many MMC1 registers you actually write to during interups that should be treated fastly.
Code to be always called before returning (IRQ and NMIs). Also NMI shouldn't enable IRQs back if used.
If anyone ever wants to enable back IRQs during NMI routine, and allow up to 3 layer of writes, but I'm pretty sure nobody will really wants to do this since NMI is supposed to execute fastly.
MMC3 write main programm routine, enter with A=Data and X=Adress :
MMC3 Routine to write to MMC3 during an interupt (NMI, IRQ) :
Again, it only alows 2 layers as it, but it would be possible to use the same concept to make 3 layers.
Disabling interupt can be a solution, but this will delay the interupt and in some case you want to avoid this. I guess I'll post some code that will allow solutions to fix this. Those allow all interupt and main code to do any mapper write all the time, if used proprely. Of course any personal variant of those will work.
MMC1 writes needs only 2 zero-page variables, while MMC3 needs only one zero-page variable.
MMC1 : Main programm MMC1 write routine. Enter with A=Data to write and Y=High byte to adress you'd want to write to ($80-$9f for reg0, $a0-$bf for reg1, etc...). X is unnafected.
Code:
MMC1Write_Main
sta MMC1WriteData
sty MMC1WriteAdress
ldy #$05
inc MMC1WriteFlag
- sta [MMC1WriteAdress-1],Y ;Note that low byte doesn't matter. Last write always write to the good page since Y is zero
lsr A
dey
bne - ;Those who want faster performence can unroll this loop
dec MMC1WriteFlag
rts
sta MMC1WriteData
sty MMC1WriteAdress
ldy #$05
inc MMC1WriteFlag
- sta [MMC1WriteAdress-1],Y ;Note that low byte doesn't matter. Last write always write to the good page since Y is zero
lsr A
dey
bne - ;Those who want faster performence can unroll this loop
dec MMC1WriteFlag
rts
MMC1 : Code to write to the MMC1 in Reset, IRQ and/or NMI code (enter with A=Data to write). I use a fixed adress for faster performance, but it's also possible to implement it the fashion as it's above. You'd typically make as many copies of it as many MMC1 registers you actually write to during interups that should be treated fastly.
Code:
MMC1Write_Int
inc Dummy ;Make a PRG write with bit 7 set, to reset write counter
sta $f000
lsr A
sta $f000
lsr A
sta $f000
lsr A
sta $f000
lsr A
sta $f000
rts
Dummy
.db $80
inc Dummy ;Make a PRG write with bit 7 set, to reset write counter
sta $f000
lsr A
sta $f000
lsr A
sta $f000
lsr A
sta $f000
lsr A
sta $f000
rts
Dummy
.db $80
Code to be always called before returning (IRQ and NMIs). Also NMI shouldn't enable IRQs back if used.
Code:
lda MMC1WriteFlag
beq +
dec MMC1WriteFlag ;Reset the flag
lda MMC1WriteData
jsr MMC1Write_Main+4 ;Don't store adress and data, but load them instead
pla ;Restore Y (useless)
pla
tax ;Restore X
pla ;Restore A (useless)
plp ;Restore P (exept Z and N flags which are affected, but who cares)
pla ;Discard return adress of MMC1Writa_Main (as the write is done)
pla
rts
+ pla
tay
pla
tax
pla
rti
beq +
dec MMC1WriteFlag ;Reset the flag
lda MMC1WriteData
jsr MMC1Write_Main+4 ;Don't store adress and data, but load them instead
pla ;Restore Y (useless)
pla
tax ;Restore X
pla ;Restore A (useless)
plp ;Restore P (exept Z and N flags which are affected, but who cares)
pla ;Discard return adress of MMC1Writa_Main (as the write is done)
pla
rts
+ pla
tay
pla
tax
pla
rti
If anyone ever wants to enable back IRQs during NMI routine, and allow up to 3 layer of writes, but I'm pretty sure nobody will really wants to do this since NMI is supposed to execute fastly.
MMC3 write main programm routine, enter with A=Data and X=Adress :
Code:
MMC3Write_Main
stx MMC3AdressLatch
stx $8000
sta $8001
rts
stx MMC3AdressLatch
stx $8000
sta $8001
rts
MMC3 Routine to write to MMC3 during an interupt (NMI, IRQ) :
Code:
MMC3Write_Int
stx $8000
sta $8001
lda MMC3AdressLatch
sta $8000
rts
stx $8000
sta $8001
lda MMC3AdressLatch
sta $8000
rts
Again, it only alows 2 layers as it, but it would be possible to use the same concept to make 3 layers.