SMB 3 spiked ceilings in castles bug

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
SMB 3 spiked ceilings in castles bug
by on (#122975)
Well, I know there's something wrong with my mapper 4 implementation (probably IRQ counter related) that has to be causing this one. Any idea which aspect of it I should be looking at first that could be making this nastiness happen?

Image

:x
Re: SMB 3 spiked ceilings in castles bug
by on (#122977)
irq? sprite 0?
Re: SMB 3 spiked ceilings in castles bug
by on (#122984)
3gengames wrote:
irq? sprite 0?


AFAIK there is no Sprite 0 timing in SMB3. It looks like IRQ to me alright.

How is the rest of the game? How are other Mapper 004 games? Does your emu pass the MMC3 tests?
Re: SMB 3 spiked ceilings in castles bug
by on (#122986)
Are you setting the period counter to zero when $C001 is written? Do you reload it with the most recent value written to $C000 when it's clocked by the scanline counter while being zero?

I'd mark up lines where IRQs are being asserted and look at that along with a textual trace of MMC3 IRQs.
Re: SMB 3 spiked ceilings in castles bug
by on (#122991)
Post your IRQ code from mapper 4 source/VBlank.
Re: SMB 3 spiked ceilings in castles bug
by on (#122999)
ulfalizer wrote:
Are you setting the period counter to zero when $C001 is written? Do you reload it with the most recent value written to $C000 when it's clocked by the scanline counter while being zero?

I'd mark up lines where IRQs are being asserted and look at that along with a textual trace of MMC3 IRQs.


AH! I was doing this on write to $C000/$C001:

Code:
            if (addr & 1) map4->irqcounter = 0;
               else map4->irqlatch = value;



Changing it to this:

Code:
            if (addr & 1) map4->irqcounter = map4->irqlatch;
               else map4->irqlatch = value;



Gives me this:

Image


Much better, but my mapper 4 implementation is still slightly off though. You can see how the first scanlines where the IRQs happen are shifted sideways a bit. Also, when vertically scrolling the screen (i.e. Mario flying or the spiked ceilings moving) everything under where the IRQ scanline was is a little unstable. It's tough to explain. If you want to see what I mean, here's the exe I just compiled:

http://rubbermallet.org/currentmoarnes.zip

Turn into raccoon Mario on the first level of SMB 3 and start flying up into the sky and watch the status bar as you do it to see what I mean!
BTW, there are four quicksave slots in MoarNES. F1 through F4 saves state, F5 through F8 loads them again.
Re: SMB 3 spiked ceilings in castles bug
by on (#123000)
WedNESday wrote:
3gengames wrote:
irq? sprite 0?


AFAIK there is no Sprite 0 timing in SMB3. It looks like IRQ to me alright.

How is the rest of the game? How are other Mapper 004 games? Does your emu pass the MMC3 tests?


The game is still fully playable. I don't pass the MMC3 tests. I tried using them a while back, but I wasn't getting anywhere with them. Asking about things here usually helps more. :)

Most other mapper 4 games have odd glitches to some extent too. TMNT 2 for example:

Image

Looks like the wrong CHR bank is being used there or something.
Re: SMB 3 spiked ceilings in castles bug
by on (#123001)
Zepper wrote:
Post your IRQ code from mapper 4 source/VBlank.


I do this at the start of each frame where I turn off the vblank flag for the first scanline:

Code:
   if (cartridge.mapper == 4) map4->irqcounter = map4->irqlatch;



At the beginning of every scanline I run map4work() which is:

Code:
void map4work() {
   if (cartridge.mapper == 4) {
      if (map4->irqenable && map4->irqcounter == 0) irq6502();
      if (map4->irqcounter == 0) map4->irqcounter = map4->irqlatch;
      if (PPU->bgvisible || PPU->sprvisible) map4irqdecrement();
   }
}
Re: SMB 3 spiked ceilings in castles bug
by on (#123002)
In most MMC3 games, your map4work should be done at the first sprite fetch (dot 261 of the line), not at the beginning of the line. (Actually, it should be done when the PPU address switches from $0xxx or $2xxx to $1xxx for the first time in each scanline.)
Re: SMB 3 spiked ceilings in castles bug
by on (#123003)
miker00lz wrote:
ulfalizer wrote:
Are you setting the period counter to zero when $C001 is written? Do you reload it with the most recent value written to $C000 when it's clocked by the scanline counter while being zero?

I'd mark up lines where IRQs are being asserted and look at that along with a textual trace of MMC3 IRQs.


AH! I was doing this on write to $C000/$C001:

Code:
            if (addr & 1) map4->irqcounter = 0;
               else map4->irqlatch = value;



Changing it to this:

Code:
            if (addr & 1) map4->irqcounter = map4->irqlatch;
               else map4->irqlatch = value;


The old version before the change is what I have. irqcounter is only ever reloaded from irqlatch as the result of a clock from the scanline counter - never as a result of writing one of the MMC3 registers.

To be more specific, irqlatch is copied to irqcounter when you get a clock from the scanline counter and irqcounter equals zero.

The fact that your change "almost" fixes things suggests something might be wrong with your scanline counting or reloading logic. Normally the value of irqcounter would go 0, irqlatch, irqlatch - 1, ..., where the initial 0 is from the $C001 write and the decrements are from scanline clocks. In your version it'll go irqlatch, irqlatch - 1, irqlatch - 2, ... instead, which probably is why it's off by one. I would check that the 0-to-irqlatch transition on the first scanline clock is working as expected first.
Re: SMB 3 spiked ceilings in castles bug
by on (#123004)
miker00lz wrote:
Zepper wrote:
Post your IRQ code from mapper 4 source/VBlank.


I do this at the start of each frame where I turn off the vblank flag for the first scanline:

Code:
   if (cartridge.mapper == 4) map4->irqcounter = map4->irqlatch;


This shouldn't be needed. The MMC3 itself doesn't keep track of frames.


miker00lz wrote:
At the beginning of every scanline I run map4work() which is:

Code:
void map4work() {
   if (cartridge.mapper == 4) {
      if (map4->irqenable && map4->irqcounter == 0) irq6502();
      if (map4->irqcounter == 0) map4->irqcounter = map4->irqlatch;
      if (PPU->bgvisible || PPU->sprvisible) map4irqdecrement();
   }
}


With this approach you'd want everything to be conditional on PPU->bgvisible || PPU->sprvisible. That's required for the MMC3 to see scanlines, and the scanline clocks are what trigger other events. Also note that reloading and decrementing irqcounter is an either-or thing: You should never both reload and decrement it during the same clock.
Re: SMB 3 spiked ceilings in castles bug
by on (#123022)
I tested out Slalom, and can see that the scrolling code is buggy. But MMC3 emulation is solid enough to run my Chu Chu Rocket game correctly. So weird to see Chu Chu Rocket running correctly, but other games getting completely screwed up.