I'm currently using MMC3 for my game. Accounting for dropped frames I discovered I needed to make chr bankswapping atomic with sprite updates, as in the following. That part works fine.

What's really mysterious is that I'm now getting glitches with background chr-data. I've verified in the debugger my two variables bg_chr_bank0 and bg_chr_bank1 *are not modified* when this glitch occurs.

I'm having trouble imagining what else could be wrong, here. I know MMC3 is not subject to bus conflicts.

This is from my current nmi routine. All chr-rom banks are updated every frame based on what was calculated in the previous frame. I currently do not protect the bg chr updates the way I protect the spr chr updates, however, I verified that these values are not changing, yet the glitches appear in the bg tiles and nowhere else (they select the wrong tiles).

What's really mysterious is that I'm now getting glitches with background chr-data. I've verified in the debugger my two variables bg_chr_bank0 and bg_chr_bank1 *are not modified* when this glitch occurs.

Does your "main thread" perform MMC3 writes? If so, something like this could happen:

What's really mysterious is that I'm now getting glitches with background chr-data. I've verified in the debugger my two variables bg_chr_bank0 and bg_chr_bank1 *are not modified* when this glitch occurs.

Does your "main thread" perform MMC3 writes? If so, something like this could happen:

One way to prevent races is to set a policy that only the IRQ and NMI handlers ever change any window register other than 7 (PRG bank in CPU $A000-$BFFF), and they must select window register 7 before returning. This may be inconvenient if your main thread switches $8000-$9FFF and $A000-$BFFF independently. But it's convenient if your main thread switches only $A000-$BFFF, such as if you're using fixed $8000-$9FFF and $E000-$FFFF (P bit set in register select) and switching DPCM in window 6 (CPU $C000-$DFFF). Thus only the NMI handler and PIT IRQ handler change windows 0-5, and only the audio engine (called by the NMI handler) ever changes window 6 ($C000).

So there are two writes to bank select in a row. I don't understand why that doesn't (always) work without implementing my own lock of some kind. Shouldn't writing to the select register more than once just reset the state and expect a data write right after?

The only "state" of the window select register ($8000) is A. which window (0-7) will be changed when a bank number is written to $8001, B. whether CPU $8000 and $C000 are swapped, and C. whether PPU $0000 and $1000 are swapped.

Writing $06 then $01 to $8000 then writing $02 then $03 to $8001 will not affect window 6. It will only switch window 1 to bank $02 then bank $03. There is no stack of window select states unless you implement one in software.

So there are two writes to bank select in a row. I don't understand why that doesn't (always) work without implementing my own lock of some kind. Shouldn't writing to the select register more than once just reset the state and expect a data write right after?

The effect is that the data that was meant to go to the PRG register ends up going to the CHR register instead, and both banks end up wrong.

One way to deal with this is to keep a shadow copy of "bank select from non-interrupt thread" in RAM, and have the interrupt thread restore it before RTI'ing. i.e. every time you bank switch from the non-interrupt thread, do this:

Code:

lda whateversta shadowbankselsta $8000

and at the end of your NMI handler do this:

Code:

lda shadowbankselsta $8000rti

Note that you must write to the shadow register before writing to the real register. If you wonder why, think about what happens if the interrupt fires between the two writes.

Quietust, AWJ, thanks! Storing a shadow register of the bank select fixed the issue for me. Funny thing is I had been using the shadow register, store first technique with UnROM in the past, I am not sure why it wasn't obvious to me how to apply the same technique to mmc3.

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum