Scroll glitches in Mario and Excitebike

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Scroll glitches in Mario and Excitebike
by on (#100501)
I mentioned this in another thread but figured I'd post with some screenshots since I'm still having difficulty isolating exactly what's wrong. Tepples suggested that it might be mixed writes to the PPU registers but I validated that they look okay after chasing a non-bug. Anyways, this issue only shows up in these two games, though I believe it is also the culprit behind scrolling issues that I have in Zelda:
ImageImage
Basically the top part of the screen appears to scroll but the lower part seems to "snap" in after the leftmost nametable has been completely replaced. Also, the scrolling of the top half is rarely correct. For example, in Excitebike if a hill is shown on the top half of the screen it's often flat terrain when you drive past (though not always). Games like Castlevania 1 and 2, Mega Man 1 and 2, Duck Tales, etc all scroll just fine. It seems these two have something in common that I can't figure out.

And for a bonus question, has anybody seen a case in Zelda 1 where leaving a house bumps you immediately back inside? When I walk into the house where you get the brown sword it works, but when you leave Link immediately re-enters. Makes the game obviously unplayable since you can't leave and get into a sort of endless loop.
Re: Scroll glitches in Mario and Excitebike
by on (#100511)
fergus_maximus wrote:
the lower part seems to "snap" in after the leftmost nametable has been completely replaced. Also, the scrolling of the top half is rarely correct. For example, in Excitebike if a hill is shown on the top half of the screen it's often flat terrain when you drive past (though not always).

These problem appear to be related to name table mirroring. Are you handling vertical/horizontal mirroring correctly?

I have no idea why only part of the screen would scroll though... there isn't supposed to be any screen splits after the SMB logo.
Re: Scroll glitches in Mario and Excitebike
by on (#100517)
tokumaru wrote:
These problem appear to be related to name table mirroring. Are you handling vertical/horizontal mirroring correctly?

I have no idea why only part of the screen would scroll though... there isn't supposed to be any screen splits after the SMB logo.


As far as I can tell the mirroring is working, and other games across both vertical and horizontal mirroring work fine. Here are my tests for vertical/horizontal mirroring (that pass):
Code:
func TestVerticalNametableMirroring(test *testing.T) {
   p = new(Ppu)
   p.Init()

    p.Nametables.SetMirroring(MirroringVertical)

   p.VramAddress = 0x2000
   p.WriteData(0x11)
   p.VramAddress = 0x2110
   p.WriteData(0x22)
   p.VramAddress = 0x2220
   p.WriteData(0x33)
   p.VramAddress = 0x2330
   p.WriteData(0x44)
   p.VramAddress = 0x2338
   p.WriteData(0x55)

   verifyValue(0x2000, 0x11, test)
   verifyValue(0x2800, 0x11, test)

   verifyValue(0x2110, 0x22, test)
   verifyValue(0x2910, 0x22, test)

   verifyValue(0x2220, 0x33, test)
   verifyValue(0x2A20, 0x33, test)

   verifyValue(0x2330, 0x44, test)
   verifyValue(0x2B30, 0x44, test)

   verifyValue(0x2338, 0x55, test)
   verifyValue(0x2B38, 0x55, test)

   p.VramAddress = 0x2400
   p.WriteData(0x11)
   p.VramAddress = 0x2510
   p.WriteData(0x22)
   p.VramAddress = 0x2620
   p.WriteData(0x33)
   p.VramAddress = 0x2730
   p.WriteData(0x44)
   p.VramAddress = 0x2738
   p.WriteData(0x55)

   verifyValue(0x2400, 0x11, test)
   verifyValue(0x2C00, 0x11, test)

   verifyValue(0x2510, 0x22, test)
   verifyValue(0x2D10, 0x22, test)

   verifyValue(0x2620, 0x33, test)
   verifyValue(0x2E20, 0x33, test)

   verifyValue(0x2730, 0x44, test)
   verifyValue(0x2F30, 0x44, test)

   verifyValue(0x2738, 0x55, test)
   verifyValue(0x2F38, 0x55, test)
}

func TestHorizontalNametableMirroring(test *testing.T) {
   p = new(Ppu)
   p.Init()

    p.Nametables.SetMirroring(MirroringHorizontal)

   p.VramAddress = 0x2000
   p.WriteData(0x11)
   p.VramAddress = 0x2110
   p.WriteData(0x22)
   p.VramAddress = 0x2220
   p.WriteData(0x33)
   p.VramAddress = 0x2330
   p.WriteData(0x44)
   p.VramAddress = 0x2338
   p.WriteData(0x55)

   verifyValue(0x2000, 0x11, test)
   verifyValue(0x2400, 0x11, test)

   verifyValue(0x2110, 0x22, test)
   verifyValue(0x2510, 0x22, test)

   verifyValue(0x2220, 0x33, test)
   verifyValue(0x2620, 0x33, test)

   verifyValue(0x2330, 0x44, test)
   verifyValue(0x2730, 0x44, test)

   verifyValue(0x2338, 0x55, test)
   verifyValue(0x2738, 0x55, test)

   p.VramAddress = 0x2800
   p.WriteData(0x11)
   p.VramAddress = 0x2910
   p.WriteData(0x22)
   p.VramAddress = 0x2A20
   p.WriteData(0x33)
   p.VramAddress = 0x2B30
   p.WriteData(0x44)
   p.VramAddress = 0x2B38
   p.WriteData(0x55)

   verifyValue(0x2800, 0x11, test)
   verifyValue(0x2C00, 0x11, test)

   verifyValue(0x2910, 0x22, test)
   verifyValue(0x2D10, 0x22, test)

   verifyValue(0x2A20, 0x33, test)
   verifyValue(0x2E20, 0x33, test)

   verifyValue(0x2B30, 0x44, test)
   verifyValue(0x2F30, 0x44, test)

   verifyValue(0x2B38, 0x55, test)
   verifyValue(0x2F38, 0x55, test)
}


WriteData() is the function that handles writes to $2007, all verifyValue() does is compare the value at that location in the nametables to the provided value.
Re: Scroll glitches in Mario and Excitebike
by on (#100527)
Moved thread to NESemdev board, since this is emulation-related.
Re: Scroll glitches in Mario and Excitebike
by on (#100530)
tokumaru wrote:
fergus_maximus wrote:
the lower part seems to "snap" in after the leftmost nametable has been completely replaced. Also, the scrolling of the top half is rarely correct. For example, in Excitebike if a hill is shown on the top half of the screen it's often flat terrain when you drive past (though not always).

These problem appear to be related to name table mirroring. Are you handling vertical/horizontal mirroring correctly?

I have no idea why only part of the screen would scroll though... there isn't supposed to be any screen splits after the SMB logo.


The screenshot of SMB is obviously after the demo mode has kicked in...

Looks to me more like sprite 0 hit is off by one [or more] scanlines. And the top-left sprite of mario's head at top-left of the screen perhaps the sprites being set to off-screen area (their Y-coord is $F8, X-coord is $00) isn't working properly. Sure enough the OAM is filled with the top-left of mario's head.
Re: Scroll glitches in Mario and Excitebike
by on (#100531)
All the working examples you gave have mapper controlled mirroring but both SMB and Excitebike use NROM. Check that you are setting mirroring correctly for non-mapper controlled mirroring.
Re: Scroll glitches in Mario and Excitebike
by on (#100545)
cpow wrote:
The screenshot of SMB is obviously after the demo mode has kicked in...

But why is only the logo scrolling out of the screen? IIRC, the whole screen (except the status bar) scrolls.
Re: Scroll glitches in Mario and Excitebike
by on (#100546)
cpow wrote:
Looks to me more like sprite 0 hit is off by one [or more] scanlines. And the top-left sprite of mario's head at top-left of the screen perhaps the sprites being set to off-screen area (their Y-coord is $F8, X-coord is $00) isn't working properly. Sure enough the OAM is filled with the top-left of mario's head.

What are the rules for sprites in the offscreen area? Just ignore them? That top-left sprite actually pops up in nearly every game, I didn't know if it was harmless or what.
Re: Scroll glitches in Mario and Excitebike
by on (#100547)
Sprite coordinates aren't negative, so sprites at Y=255 are not at Y=-1, they are out of range, so they are never evaluated.

Also, it looks like at around scanline 138, it stops scrolling correctly in both games. Hope you don't have any bad for loops that are stopping too early.

How about the full list of 2000 and 2005/2006 writes that happen during a particular frame, and the timestamp (scanline and dot number) that each write occurs at? If there are any writes that aren't supposed to exist, that would suggest a CPU problem. If the writes match other emulators, then it's a PPU emulation problem.
Re: Scroll glitches in Mario and Excitebike
by on (#100551)
Dwedit wrote:
Sprite coordinates aren't negative, so sprites at Y=255 are not at Y=-1, they are out of range, so they are never evaluated.

Hrmph. I'm not seeing any sprites with a 255 Y. Probably will have to revisit how I'm doing DMA and verify everything there. That sprite is getting evaluated because it's at (0, 0). It also pops up briefly on the black screen before the title screen appears, it's in Zelda, Castlevania 2, literally everywhere. You can't see it in the Excitebike screenshot because I believe the sprite it's using is the audience.

Dwedit wrote:
How about the full list of 2000 and 2005/2006 writes that happen during a particular frame, and the timestamp (scanline and dot number) that each write occurs at? If there are any writes that aren't supposed to exist, that would suggest a CPU problem. If the writes match other emulators, then it's a PPU emulation problem.

Good idea, here's a sampling that I loosely compared with JSNES (JSNES and vNES use a weird method of counting scanlines so it's difficult to sync up completely, but I verified the writes are the same for specific frames though despite the timestamp being different):

Code:
<------------------->
31.274 -> $2005: 0x42
31.298 -> $2005: 0x0
31.331 -> $2000: 0x15
124.193 -> $2000: 0x95
241.45 -> $2000: 0x14
241.177 -> $2005: 0x0
241.189 -> $2005: 0x0
242.22 -> $2006: 0x20
242.55 -> $2006: 0x95
242.148 -> $2000: 0x15
246.332 -> $2006: 0x3F
247.9 -> $2006: 0x0
247.21 -> $2006: 0x0
247.33 -> $2006: 0x0
247.84 -> $2005: 0x0
247.96 -> $2005: 0x0
<------------------->
31.261 -> $2005: 0x44
31.285 -> $2005: 0x0
31.318 -> $2000: 0x15
101.282 -> $2000: 0x95
241.44 -> $2000: 0x14
241.176 -> $2005: 0x0
241.188 -> $2005: 0x0
242.21 -> $2006: 0x3F
242.54 -> $2006: 0xC
242.150 -> $2000: 0x11
243.169 -> $2006: 0x3F
243.187 -> $2006: 0x0
243.199 -> $2006: 0x0
243.211 -> $2006: 0x0
243.262 -> $2005: 0x0
243.274 -> $2005: 0x0
<------------------->
31.272 -> $2005: 0x44
31.296 -> $2005: 0x0
31.329 -> $2000: 0x11
122.56 -> $2000: 0x91
241.43 -> $2000: 0x10
241.175 -> $2005: 0x0
241.187 -> $2005: 0x0
242.17 -> $2005: 0x0
242.29 -> $2005: 0x0
<------------------->
Re: Scroll glitches in Mario and Excitebike
by on (#100554)
Is that for Super Mario Bros?
FCEUX doesn't show any writes to $2000 at scanline 124, 101, or 122. The second $2000 write should happen on the same scanline, 69 dots later.
EDIT: oops, that's only true if the game is paused. When running, the second 2000 write does indeed come much later.

The scroll writes ($2005) after the sprite the sprite 0 hit are also about 100 dots late. FCEUX sees them happening at times around 97 or 104, not 261 or 274.

Are you setting X scroll to 0 when it sees a 2000 write, or something like that?
Re: Scroll glitches in Mario and Excitebike
by on (#100566)
Dwedit wrote:
Is that for Super Mario Bros?
FCEUX doesn't show any writes to $2000 at scanline 124, 101, or 122. The second $2000 write should happen on the same scanline, 69 dots later.
EDIT: oops, that's only true if the game is paused. When running, the second 2000 write does indeed come much later.

The scroll writes ($2005) after the sprite the sprite 0 hit are also about 100 dots late. FCEUX sees them happening at times around 97 or 104, not 261 or 274.

Are you setting X scroll to 0 when it sees a 2000 write, or something like that?

Nope, the only line affecting the VRAM address in a write to $2000 is this
Code:
p.VramLatch = (p.VramLatch & 0x73FF) | ((int(v) & 0x03) << 10)

If the writes to $2005 after sprite0 is hit are late, that would probably imply that I'm setting the sprite0 hit flag too late then?

And yeah, was SMB ;) sorry
Re: Scroll glitches in Mario and Excitebike
by on (#100723)
Gah, finally found it. You were right Dwedit, scroll was being set to 0 inadvertently by a typo where I was resetting the VRAM latch to zero, not the first/second write toggle. Scrolling is working great now in both games. Looks like I have something yet to fix though since Mario just gets stuck in midair when you start playing the game though.

Here's tepples post that I used to solve the issue: viewtopic.php?p=21745#p21745