I understand about the A12 rises and how the counter works and all that. My issue is with the timing.
I have Blargg's MMC3 tests passing, as well as the titlescreen of Kick Master and in-game Wolverine working glitch-free (have yet to test some other problem points in Kick Master -- but I'm confident they'll be fine). It's HOW I got them working that concerns me...
I understand that A12 rises on the 5th cycle of every 8 fetch cycles (4, 12, 20, 28, etc for BG fetches if BG uses $1xxx.... 260,268, etc for Sprite fetches when they use $1xxx)
I built my emu to clock the counter at these times, then ran the test ROMs. Blargg's gave me a "too early" error, so I pushed it back a few cycles (I figured it was due to my PPU/CPU sync method -- perhaps it would have to go THROUGH the cycle rather than up to the cycle or something like that -- making an off-by-1 error likely (and even expected)).
However I was concerned when I found out I had to push the time back THREE ppu cycles from the norm in order to get a passing result in blargg's test. And even more (9!) to get Wolverine and Kick Master working without jitters -- and even up to 11! (where I have it now) to clear some garbage that appears on the right-hand side of the screen in Wolverine. (blargg's tests seem to pass when I adjust 3-11 cycles inclusive, but fail outside of that)
There's no way my calculations could be 11 cycles off... that's too big of a gap to chalk it up to ppu/cpu/mapper sync issues. But then this made me think back to an issue I had with APU IRQs... and how when I tripped an IRQ exactly when the frame IRQ flag raised, I got errors. I ended up solving the problem by adding a delay of 2 CPU cycles between when the IRQ flag raised and when the IRQ actually happened. Currently I only do that for APU Frame IRQs... but is that the case for EVERY IRQ? That might explain the 11 cycle offset -- 2 CPU cycles would eat at least 6 cycles of that. But that still leaves 5 ppu cycles of "adjust" time in my MMC3 code (could it be a 3 CPU cycle delay?)
I'm going to mess around with this some more and will probably report back with more crap. This whole thing of delays and stuff is a pain... why can't IRQs just happen immediately ;_;
While I'm on the subject -- anyone have any good recommendations for MMC3 problem games which make good test ROMs? My list is basically:
- Mega Man 3 (it has BG and sprites both use the $1xxx pattern table for the pause-status bar -- Pausing in the first half of Gemini Man's stage will glitch if you don't handle that properly)
- Crystalis (scanline -1 checking -- otherwise the screen shifts when you talk to people and there's that garbage line as you scroll on the map)
- Kick Master, Wolverine (both just generally very picky about timing -- Kick Master also does weird things and will deadlock if IRQs trip when they shouldn't (end of stage 2))
I'd really like some games which use a backwards setup (BG uses $1xxx, sprites use $0xxx) or other weird behavior like that so I can test. If anyone can recommend some like that or just some they have trouble with I'd be grateful.
Added the 2 cpu cycle delay between IRQ flag raise and actual IRQ tripping. Still need to adjust my MMC3 code by 3 ppu cycles (which is what I expected -- but that still seems like too much... 1 cycle if any, should be enough). If I up the delay to 3 CPU cycles, then my Frame IRQs come in too late according to blargg's tests.
Could MMC3 IRQs somehow be slower to register than APU IRQs? Is it possible there's a 3 CPU cycle gap for MMC3 but only a 2 cycle gap for APU Frame IRQs?
gah my brain!
EDIT AGAIN -
Bah it just dawned on me that 3 PPU cycles = 1 CPU cycle -- and it being off by 3 PPU cycles is explained by the PPU/CPU sync issue (it has to go THROUGH the cycle rather than just UP TO the cycle). So I guess I answered all of my questions then XD. Although I'd still like test ROM recommendataions -- plus this post might help someone else *shrug*
I'm not sure if IRQ handling is 100% correct. Problem games:
- Armadillo: statusbar shakes in-game
- Days of Thunder: screen shakes when entering/exiting pits. garbage scanline on the game over textbox (not in PAL version)
- Juuouki: statusbar shakes in-game
- Mickey's Safari in Letterland: bottom half of statusbar shakes in-game
- Super Mario Bros 3 (J): white line above the 'checkerboard' shouldn't be visible on the Famicom (different MMC3 revision?), should be on NES though
- Ys III: statusbar shakes at the first conversation (pending IRQs are involved)
Nintendulator shares them as well (at least the games I checked -- except it seemed to run Armadillo just fine).
Ys III was TOTALLY borked in both my emu and Nintendulator. Weird fadeouts at weird times, the first conversation wasn't even visible (only the sprites and the status bar were). Is my ROM bad or what?
Some other games from the top of my head I used to have problems with:
- Time Zone: status bar shaking on the 3rd level, needed precise MMC3 interrupt timing
- Downtown Special - Kunio-kun no Jidaigeki Dayo Zenin Shuugou!: my MMC3 interrupt implementation used to be off by 1 PPU cycle, that caused this game's status screen to shake sometimes
And another one I think everyone knows about: SMB3 checkerboard shaking when the title scrolls down, MMC3 counter gets clocked twice in one scanline.
Remember that the timing has to be in relation to something, so a failing timing tests means that one of the two events being timed is off. Looking at my MMC3 timing test, the timing reference point is based on my PPU synchronization routine. That relies the timing of bit 7 when reading $2002 and the PPU's frame length when all rendering is disabled. But I'm assuming you have the PPU VBL/NMI test ROMs passing, so those should rule out any error for this timing reference point.Disch wrote:If I up the delay to 3 CPU cycles, then my Frame IRQs come in too late according to blargg's tests.
Wouldn't surprise me. I think you're pushing past what is known. I hope that some day we know exactly what happens in these cases, and why.Could MMC3 IRQs somehow be slower to register than APU IRQs? Is it possible there's a 3 CPU cycle gap for MMC3 but only a 2 cycle gap for APU Frame IRQs?
So as I understand it from Disch's MMC3 doc...the IRQ reload request register ($C001-$DFFF, odd) doesn't _directly_ force the IRQ counter to reload itself from the IRQ latch value. What it really does is actually cause the IRQ counter to be *cleared* to 0, which _then_ causes the IRQ counter to be reloaded at the end of the next scanline since that's what naturally occurs when the IRQ counter is 0.
So really the IRQ reload command register causes an *indirect* reload of the IRQ counter register. Is that correct?
Another question I have is: does this manual reload cause an IRQ to occur (since what the reload command really does, as per the above, is clear the counter to 0 and cause a reload which would normally cause an interrupt)? In this case, let's assume the reload latch value is non-zero - to make things simpler.
UPDATE: I think reading Blargg's doc and the Wiki have cleared this up. Specifically, the Wiki says:
So that tells me that my interpretation of Disch's doc was correct in that the "reload counter" register is really a "clear counter" register. In my opinion this should really be fixed on the Wiki cause it is technically incorrect. I'd be happy to change it myself if someone replies to this post and agrees with me.Writing to $C001 will cause the counter to be reloaded on the NEXT rising edge of PPU A12...
And Blargg's doc says:
And the above tells me that the answer to my second question is NO. Doing a manually clear of the IRQ counter does _not_ cause an interrupt.The IRQ flag is not set when the counter is cleared by writing to $C001.
Haha...put enough of these docs together and you can draw some pretty precise conclusions.
This especially makes sense when you look at RAMBO-1's "reset with X+1" quirk. RAMBO-1 probably has the same reset flag, and merely checks for zero before the decrement rather than after it.
/me adds to list of things to change in his docs
- The IRQ counter is at a value of 1.
- At the end of the next scanline the count will be decremented to 0 and an interrupt to the CPU will occur.
HOWEVER, _before_ the end of the next scanline the user writes to $C001, thereby requesting that the IRQ counter be cleared.
Now, at the end of the next scanline the IRQ controller sees the "Clear Request" flag has been asserted. So the IRQ counter is cleared to 0, _but_ _no_ interrupt is asserted.
Then, at the end of the next scanline the IRQ counter is reloaded with the latch value since the IRQ count value was cleared to 0 by the user in the previous scanline.
Is that a proper sequence of events?
It's more like it's requesting it be reset, not cleared.HOWEVER, _before_ the end of the next scanline the user writes to $C001, thereby requesting that the IRQ counter be cleared.
The whole "cleared" thing is almost like a hackish way to make it reset because it will reset when it's at zero.
It wouldn't be cleared to zero. It would be reset to whatever was last written to $C000.Now, at the end of the next scanline the IRQ controller sees the "Clear Request" flag has been asserted. So the IRQ counter is cleared to 0, _but_ _no_ interrupt is asserted.
You only set it to zero if you're not doing the "reset flag" thing. If you do both, you're adding a scanline delay to the counter.
Other than that detail, I think you have it.
Basically it's like this:
On $C000 write:
- set 'LATCH' to value written
On $C001 write:
- set "reset counter" flag
On IRQ clock (every scanline)
- if "reset counter" flag is set:
-- clear the "reset counter" flag
-- set IRQ counter to LATCH
-- do not generate an IRQ
- otherwise ("reset counter" flag was not set)
-- decrement IRQ counter (wrap 0 -> LATCH)
-- if IRQ counter is zero after decrementing, and if IRQs are enabled, generate an IRQ.
May I make one suggestion though? I would change the "clear" term that you use in your mapper 4 MMC3 doc to "reset". It was really confusing me - when I think "clear" I think clear vs. set (as in bits) - so "clear" would mean value goes to 0. But that's not really what happens. The counter is really "reset" to the last value written to $C000. Now that I understand this all three docs (yours, Blargg's, and the Wiki's) match up! This is just my opinion...but I really think it would help.
It would also be awesome if you added this "reset flag" method. That really helped me as well.
Haha, I would even add the last part of your post to the doc as well - straightened me out good!
THANKS FOR ALL YOUR HELP DISCH!!!
Oh...and if you do make any of those changes can you send me your new 004.txt file?? Pretty please? You can send it to "webmaster" at my website's domain name.
Code: Select all
wire irq; assign irq = irq_en & ~|counter; assign reset_count = reset_latch | ~|counter; // reset_latch should be set on C001 writes, cleared on irq_check always @(posedge clk) if (irq_check) if (reset_count) counter <= latch; else counter <= counter - 1'b1;