MMC3, IRQs, Bank swaps and crashes

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
Denine
Posts: 395
Joined: Wed Feb 17, 2010 5:42 pm

MMC3, IRQs, Bank swaps and crashes

Post by Denine » Tue Feb 12, 2019 11:53 am

Hi,
Im working on a MMC3 game, it requires an IRQ to split the screen.
The split and all works quite nice, but game crashes at seemingly random intervals, which can be influenced by having player do stuff.
I was able to trace the problem to IRQ getting triggered during a bank swap:

Code: Select all

lda #somevalue
sta $8000
----IRQ happens here
lda #somevalue
----or here
sta $8001
The problem is IRQ code *needs* to swap banks for its own uses.
I was able to minimalize the frequency of crashes by:

Code: Select all

lda #somevalue
ldx #somevalue
sta $8000
----IRQ can still happen here
stx $8001
But crashes can still hapen, albeit rarely.
Does anyone more familiar with MMC3 have a workaround for this kind of thing?
I guess I could disable irqs before swapping banks and enabling them after swap is done, but that would be slow. Any ideas?

User avatar
pubby
Posts: 548
Joined: Thu Mar 31, 2016 11:15 am

Re: MMC3, IRQs, Bank swaps and crashes

Post by pubby » Tue Feb 12, 2019 12:03 pm

Never used MMC3 before but you'd probably have to keep track of the current $8000 value.

Code: Select all

lda #somevalue
sta register8000
sta $8000
lda #somevalue
sta $8001
Then in the IRC you'd put this at the end:

Code: Select all

lda register8000
sta $8000
I guess I could disable irqs before swapping banks and enabling them after swap is done, but that would be slow. Any ideas?
Maybe I misunderstand, but isn't this just a single SEI and CLI?

lidnariq
Posts: 8792
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: MMC3, IRQs, Bank swaps and crashes

Post by lidnariq » Tue Feb 12, 2019 12:06 pm

Always keep a "shadow" copy of the last value written to $8000 and the two PRG banks:

Code: Select all

lda #whatever
sta shadow8000
sta $8000

Code: Select all

lda #6
sta shadow8000
sta $8000
lda #whatever
sta shadowR6
sta $8001
Always restore registers from these shadows at the end of IRQ:

Code: Select all

lda #6
sta $8000
lda shadowR6
sta $8001
lda #7
sta $8000
lda shadowR7
sta $8001
lda shadow8000
sta $8000
rti
If there's any possibility of IRQ and NMI colliding and both needing independent bank access, it gets a lot harder.

Denine
Posts: 395
Joined: Wed Feb 17, 2010 5:42 pm

Re: MMC3, IRQs, Bank swaps and crashes

Post by Denine » Tue Feb 12, 2019 2:07 pm

I guess I could disable irqs before swapping banks and enabling them after swap is done, but that would be slow. Any ideas?
Maybe I misunderstand, but isn't this just a single SEI and CLI?[/quote]
I think SEI and CLI pair would work, but it still would be slower. What I mean, is that IRQ *needs* to start as soon as it can.
I use IRQ to do a screen split, with some palette updates in Hblank.
If I disable IRQ before bank swap and reenable after, it will start instatnly, possibly increasing jitter.
If, IRQ was to happen before turning it off in one frame, but be "queued" right after it got disabled.

Shadow registers are great idea, thanks to you both :)

lidnariq
Posts: 8792
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: MMC3, IRQs, Bank swaps and crashes

Post by lidnariq » Tue Feb 12, 2019 2:28 pm

One thing I meant to say, but left implicit: make sure you update the copy of the shadow before you update the register. If you do it in the other order a perfectly timed IRQ could mess everything up:

Code: Select all

 lda #value
 sta $8000
 --> IRQ
    pha
    lda #thing
    sta $8000
[...]
    lda shadow8000
    sta $8000
    pla
    rti
 sta shadow8000
will result in the desired value in the shadow, but the wrong value actually in the mapper

User avatar
Banshaku
Posts: 2328
Joined: Tue Jun 24, 2008 8:38 pm
Location: Fukuoka, Japan
Contact:

Re: MMC3, IRQs, Bank swaps and crashes

Post by Banshaku » Tue Feb 12, 2019 5:30 pm

The more your game becomes complicated, the more caching is important. When you need to have the sound driver and the music data switched on every frame, this mechanism will be required so the sooner the better.

I remember when I started to implement the cache for the soundriver bank switching and it was crashing all the time until I got it right ^^;;;

calima
Posts: 1021
Joined: Tue Oct 06, 2015 10:16 am

Re: MMC3, IRQs, Bank swaps and crashes

Post by calima » Wed Feb 13, 2019 1:37 am

I have a reentrancy check in my normal bank swap routine.

Code: Select all

tryagain:
swapsafe = 1;
BANKSEL = 6;
BANKFILE = num;
if (!swapsafe) goto tryagain;
With the irq routine setting it to zero.

Denine
Posts: 395
Joined: Wed Feb 17, 2010 5:42 pm

Re: MMC3, IRQs, Bank swaps and crashes

Post by Denine » Fri Feb 15, 2019 3:00 pm

The shadow method seems to work, thanks.
Banshaku wrote:The more your game becomes complicated, the more caching is important. When you need to have the sound driver and the music data switched on every frame, this mechanism will be required so the sooner the better.

I remember when I started to implement the cache for the soundriver bank switching and it was crashing all the time until I got it right ^^;;;
I had a similiar situation where nmi happened when music driver was changing track...and I have music play in nmi, so that taught me a bit :)
calima wrote:I have a reentrancy check in my normal bank swap routine.

Code: Select all

tryagain:
swapsafe = 1;
BANKSEL = 6;
BANKFILE = num;
if (!swapsafe) goto tryagain;
With the irq routine setting it to zero.
To be fair, I dont really understand what does that mean.

pwnskar
Posts: 104
Joined: Tue Oct 16, 2018 5:46 am
Location: Gothenburg, Sweden

Re: MMC3, IRQs, Bank swaps and crashes

Post by pwnskar » Mon Feb 18, 2019 10:06 am

calima wrote:I have a reentrancy check in my normal bank swap routine.

Code: Select all

tryagain:
swapsafe = 1;
BANKSEL = 6;
BANKFILE = num;
if (!swapsafe) goto tryagain;
With the irq routine setting it to zero.
But that would only cover cases where the IRQ happens during a bank swap? If the IRQ happens after the if-statement it will switch banks and have the code following it on return read from the wrong bank. Therefore you would have to have the IRQ restore the bank to it's previous state, which would make the if-statement you wrote redundant. I think so at least but I am very new to bank swapping.. :P

calima
Posts: 1021
Joined: Tue Oct 06, 2015 10:16 am

Re: MMC3, IRQs, Bank swaps and crashes

Post by calima » Mon Feb 18, 2019 11:54 am

The IRQ naturally restores the previous bank upon returning. The if is not redundant, since the IRQ can happen anywhere in there. Very careful ordering of the shadow bank var writes may or may not have the same result.

pwnskar
Posts: 104
Joined: Tue Oct 16, 2018 5:46 am
Location: Gothenburg, Sweden

Re: MMC3, IRQs, Bank swaps and crashes

Post by pwnskar » Tue Feb 19, 2019 11:26 am

calima wrote:The IRQ naturally restores the previous bank upon returning. The if is not redundant, since the IRQ can happen anywhere in there. Very careful ordering of the shadow bank var writes may or may not have the same result.
Cool, I did not know that! Is the same done with NMI?

calima
Posts: 1021
Joined: Tue Oct 06, 2015 10:16 am

Re: MMC3, IRQs, Bank swaps and crashes

Post by calima » Wed Feb 20, 2019 1:31 am

Yes, if the NMI switches banks.

Post Reply