Slight timing(?) issue

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Slight timing(?) issue

Post by lemmurg »

This scanline test is showing some corruption in my emu:
timing1.gif
timing1.gif (5.96 KiB) Viewed 4660 times
I think it's a problem with timing, but I have a hard time finding the cause. Maybe you experienced guys have some pointers?

I suspect/hope it's also the cause for this glitch in SMB that only occurs when a sprite is near the top of the screen. It renders perfectly otherwise.
timing2.gif
timing2.gif (207.9 KiB) Viewed 4660 times
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Slight timing(?) issue

Post by Dwedit »

Are you checking for collision with sprites that aren't Sprite #0?
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Slight timing(?) issue

Post by Zepper »

I have the same problem with scanline test, but no shaking.
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

Dwedit wrote: Mon May 17, 2021 5:54 am Are you checking for collision with sprites that aren't Sprite #0?
I have triple checked, I'm only testing sprite #0.

It passes these tests, except for the timing test #9. That one fails with "Flag set too soon for upper-left corner". If I add a one-cycle delay, it fails with "Flag set too late for upper-right corner" instead :?
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Slight timing(?) issue

Post by Quietust »

lemmurg wrote: Mon May 17, 2021 7:47 am
Dwedit wrote: Mon May 17, 2021 5:54 am Are you checking for collision with sprites that aren't Sprite #0?
I have triple checked, I'm only testing sprite #0.
Are you absolutely certain? There's a big difference between "the first sprite rendered on the scanline" and "the sprite located at OAM address 0", and I strongly suspect your emulator is doing the former rather than the latter.

In fact, I'm almost 99% certain that that's what you're doing, because when I edited my own emulator to drop the "scanline contains sprite #0" check from its sprite 0 hit logic, it began behaving exactly the same as depicted in your first post.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

Quietust wrote: Mon May 17, 2021 8:17 am Are you absolutely certain? There's a big difference between "the first sprite rendered on the scanline" and "the sprite located at OAM address 0", and I strongly suspect your emulator is doing the former rather than the latter.
Yes, I am certain. I'm iterating over a copy of the secondary OAM starting at index 0 and the flag can only get set during the first iteration. There is no "sort by x coordinate" anywhere in the code.

Code: Select all

// just the basic logic, not the literal code
int hitFlag = 0x40 * min(1, bgPattern);
for(int i = 0; i < numSpr; ++i) {
    // range check, etc...
   if(sprPattern[i] > 0)
    status |= hitFlag;
  hitFlag = 0;
}
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Slight timing(?) issue

Post by Dwedit »

If you look at the first sprite from secondary OAM, you'll find the first sprite rendered on the line, which is not necessarily Sprite #0. It needs to actually be sprite #0.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

Dwedit wrote: Mon May 17, 2021 8:50 am If you look at the first sprite from secondary OAM, you'll find the first sprite rendered on the line, which is not necessarily Sprite #0. It needs to actually be sprite #0.
So Sprite #0 is the one at index 0 in the primary OAM, not the one at index 0 in the secondary OAM? Really? Where does the PPU get this information from?

The first sprite rendered on the current line is the first one in secondary OAM that is in range of the current pixel's x position - that's not necessarily the first one in the secondary OAM. The sprite at OAM2[0] can be at x = 200 and the one at OAM2[4] can be at x = 10. They're not sorted by x coordinate. I'm only checking the one at OAM2[0], but I gotta check again if I misunderstood something about this.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Slight timing(?) issue

Post by Dwedit »

It would take a total of one bit of storage to indicate that Sprite 0 in secondary OAM is the same as Sprite 0 in primary OAM. You don't need anything fancy like expanding secondary OAM to include things like 'original sprite number' or 'is this sprite 0' on each sprite.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

Dwedit wrote: Mon May 17, 2021 9:11 am It would take a total of one bit of storage to indicate that Sprite 0 in secondary OAM is the same as Sprite 0 in primary OAM. You don't need anything fancy like expanding secondary OAM to include things like 'original sprite number' or 'is this sprite 0' on each sprite.
Sure, but I haven't seen anything about this flag in the docs, that's why I'm asking. Maybe I missed it.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Slight timing(?) issue

Post by Dwedit »

Using a flag is just one possible way to implement it, so that flag doesn't really formally exist anywhere, so it wouldn't be in any documentation.
The only part that matters is if it's Primary OAM Sprite #0 or not.

I don't know if the actual PPU uses a single bit of storage to define this relation, but the actual decapped chip is available to look at. It's very hard to read it.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Slight timing(?) issue

Post by Quietust »

Dwedit wrote: Mon May 17, 2021 9:26 am I don't know if the actual PPU uses a single bit of storage to define this relation, but the actual decapped chip is available to look at. It's very hard to read it.
The PPU actually has two internal registers for this: one to denote that sprite #0 was detected during evaluation for the next scanline ("[/]sprite_0_on_next_scanline", nodes #5934/#5907), and another one to denote that sprite #0 is being rendered on the current scanline ("[/]sprite_0_on_cur_scanline", nodes #5834/#1105), where the first gets copied to the second during cycles 256-319 (i.e. during the sprite CHR fetches). The signal names and node numbers refer to the Visual 2C02 simulator.
lemmurg wrote: Mon May 17, 2021 9:06 am So Sprite #0 is the one at index 0 in the primary OAM, not the one at index 0 in the secondary OAM? Really? Where does the PPU get this information from?
The actual logic is surprisingly simple - if the PPU tries to write to secondary OAM on cycle 66* (i.e. immediately after evaluating the Y-coordinate of sprite 0), then it sets the flag because it just evaluated Primary OAM slot #0 as a valid sprite; if the first matched sprite was primary OAM slot #1, then the write would've happened at cycle 68, and other sprites would be found at correspondingly later times.

(* the relevant signal in Visual 2C02 is actually named "++hpos_eq_65_and_rendering_and_pclk1", but it's delayed by several clock cycles so it doesn't trigger until hpos=66)
Last edited by Quietust on Mon May 17, 2021 10:15 am, edited 2 times in total.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

I am now a proud user of this flag and the glitch in SMB went away. Thank you!

However, the scanline test doesn't care about sprite 0 hit at all, or sprites in general. It's still flickering.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Slight timing(?) issue

Post by Quietust »

lemmurg wrote: Mon May 17, 2021 9:47 am I am now a proud user of this flag and the glitch in SMB went away. Thank you!

However, the scanline test doesn't care about sprite 0 hit at all, or sprites in general. It's still flickering.
It's been a while since I've tested scanline.nes on real hardware, but the flickering you're seeing might be a result of performing your VRAM address "vertical increment" at the wrong time.

What that ROM does is write $04->$2006/$04->$2006 just to the right of the vertical bar and then write to $2006+$2005+$2005+$2006 (to prepare the VRAM address for the next scanline) at the very right edge of the screen, so if the timing is even slightly off, it could result in the jittering you're seeing.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
lemmurg
Posts: 25
Joined: Fri May 07, 2021 3:22 pm

Re: Slight timing(?) issue

Post by lemmurg »

scanline2.png
NMI timing was off on the CPU side. Some garbage in the first area, but that's also there in NEStopia and Nintendulator, so I guess I'm good?

I'm struggling with IRQ timing in general. Bunch of test are failing, all related to interrupts. I'm not really sure how long the delay between request and execution should be. Some sources say execute as soon as the current instruction ends, others (and failing tests) say after the next instruction, plus a bunch of special cases whose implementation is gonna be pretty hacky :|
Post Reply