It is currently Fri Oct 20, 2017 2:08 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Mon May 01, 2017 8:32 pm 
Offline

Joined: Sat May 04, 2013 6:44 am
Posts: 22
Games like Super Mario Bros. and Zelda 2 put sprite 0 at the bottom-center of their status bars and then test for sprite 0 hit to know when to set a non-zero xScroll in $2005, right? In my emulator, the right half of that scanline is glitched, messing with the bottom pixels of the count counters and level numbers in SMB1, and the white bottom border of the life and magic bars in Zelda 2. The rest of the picture is fine, since I reload the X scroll values from the temp register at the end of the scanline.

I must be misunderstanding something about either the fineX register, sprite 0 hit, or both. I know that the first write to $2005 immediately overwrites fineX, and writes the new coarse X to the temp register.

1. Does fine X increment every dot, and then wrap from 7 to 0?
2. Wouldn't writing the fineX in the middle of a line make at least that line scroll unpredictably without very stringent timing?
3. If the fineX is 7 at the moment the CPU writes a 0 to the scroll register, does that cause the PPU to draw the current tile a second time, or does the coarse X increment on its own, regardless of what fineX is doing?
4. If I'm seeing a glitched half line in these games, is it because I'm somehow triggering sprite 0 hit an entire line early? If the sprite 0 hit registered one line later, then no visible glitch would occur, because the next line down is just the backdrop color from there to the right.

Thanks!


Top
 Profile  
 
PostPosted: Mon May 01, 2017 8:44 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19104
Location: NE Indiana, USA (NTSC)
Fine X does not increment. It specifies the tap off a delay line for pixels coming out of the shift register: 0 maximum delay, 7 minimum delay. If fine X is 7, and $2005 first write is written again with the same coarse X and fine X of 0, then the 7 most recently rendered background pixels will be rendered again.

See also attempts to explain fine X to a non-native speaker roughly a year ago.


Top
 Profile  
 
PostPosted: Mon May 01, 2017 8:48 pm 
Offline

Joined: Mon Sep 27, 2004 2:57 pm
Posts: 1248
At any time, the PPU always has at least 8 pixels of the scanline ready to go to the screen, those 8 pixels are in a buffer, and fineX determines which of those 8 pixels is sent to the screen. However, after a pixel is drawn, instead of fineX increasing by one, the contents of the buffer itself are shifted over by one. By changing fineX in the middle of a scanline, it'll look like you're just skipping forward or skipping back.

Another important thing to keep in mind is that sprites are actually offset by one pixel downwards. That means, if the game places a sprite at (X, Y), it will physically appear at (X, Y+1), and that does indeed affect the sprite 0 test.


Top
 Profile  
 
PostPosted: Tue May 02, 2017 11:36 am 
Offline

Joined: Sat May 04, 2013 6:44 am
Posts: 22
Thank you for helping me work this out!
tepples wrote:
If fine X is 7, and $2005 first write is written again with the same coarse X and fine X of 0, then the 7 most recently rendered background pixels will be rendered again.
The scenario in SMB1 is the reverse - the fineX is 0 for the status bar, and then after the sprite 0 hit is detected, usually becomes greater than 0. So, as I scroll, the half of the scanline after the sprite 0 hit slides between 0 and 7 pixels to the left as the player walks to the right.
Drag wrote:
Another important thing to keep in mind is that sprites are actually offset by one pixel downwards. That means, if the game places a sprite at (X, Y), it will physically appear at (X, Y+1), and that does indeed affect the sprite 0 test.
Yes, I already take that into account. I assumed that drawing the sprite and testing sprite 0 for an intersection both involve adding 1 to the OAM y coordinate.

Should I conclude from this that my scrolling code is correct? As it stands now in my emulator, if the CPU does write to $2005 and change fine X in the middle of a line, it affects the rest of that line. Is the problem that I'm reporting sprite 0 in the wrong place, causing the CPU to change the scroll too early?

Here's a screenshot showing the glitched line. You can see it's the second-to-last scanline of the status bar, not the last line.
Attachment:
File comment: Glitched line after scroll split
SMB1GlitchAfterScrollSplit.PNG
SMB1GlitchAfterScrollSplit.PNG [ 58.13 KiB | Viewed 914 times ]


Top
 Profile  
 
PostPosted: Tue May 02, 2017 12:16 pm 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 154
That suggests that either your sprite 0 hit flag timing is off, or your CPU timing is off.

It shouldn't get set until the pixel it actually hits on (in reality, a couple of dots later due to various pipeline shenaningans)

For SMB, that should be on the second to last line of the sprite, it then waits about a scanline and a half, then twiddles the scroll regs.


Top
 Profile  
 
PostPosted: Tue May 02, 2017 7:38 pm 
Offline

Joined: Sat May 04, 2013 6:44 am
Posts: 22
Thanks for the help, everyone. It turns out that while I was testing the correct pixels, including the 1 line delay for the sprite position, I forgot to include that 1 line delay when I returned the hit location. Oops.

One more bug squished, countless more to go...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 12 guests


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

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group