Sprite 0 hit test corrupts my PPU

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
monterey755
Posts: 2
Joined: Sat Jun 19, 2021 3:16 am

Sprite 0 hit test corrupts my PPU

Post by monterey755 »

I'm trying to improve my sprite 0 hit accuracy with blaarg's ppu_sprite_hit_test.

One problem I'm encountering right now is my v register is corrupted because the PPUMASK background rendering flag is turned on in the visible scanlines.

Here's what I captured from my log, the left bracket indicates the current scanline.

Code: Select all

...
[030] Write $2007 0x00 at 0x23F6
[030] Write $2007 0x00 at 0x23F7
[030] Write $2007 0x00 at 0x23F8
[030] Write $2007 0x00 at 0x23F9
[030] Write $2007 0x00 at 0x23FA
[030] Write $2007 0x00 at 0x23FB
[030] Write $2007 0x00 at 0x23FC
[030] Write $2007 0x00 at 0x23FD
[030] Write $2007 0x00 at 0x23FE
[031] Write $2007 0x00 at 0x23FF
[031] Write $2001: 0b00001010
[031] Write $2006: 0x3F
[031] Write $2006: 0x00
[031] Write $2007 0x0F at 0x3F00
[032] Write $2007 0x30 at 0x4F00
CRASH
One thing I noticed from this test ROM is that there's no usage of nmi handler to fill the vram, so my guess is I need a fairly accurate cycle counting to prevent this from happening.

My current rendering approach is by using scanline based rendering, where after each 341 PPU cycles passed, I fill my internal picture buffer in the current scanline roughly like this. I've also accounted for OAMDMA cycles but don't include it in the below example for the sake of simplicity.

Code: Select all

loop {
  let cycles = cpu.step() * 3; // number of ppu cycles executed in this cpu instruction
  
  if current_cycle + cycles >= 341 {
    fill_current_scanline_to_temp_buffer();
    current_scanline++;
    current_cycle = (current_cycle + cycles) % 341;
  } else {
    current_cycle += cycles;
  }
}
Some other ROMs that have this same problem are Super Arabian and blaarg's oam_read test.

Question:
1. Am I going in the right direction in guessing that cycle accuracy is the problem?
2. If yes, what should I do about this? Should I just go with cycle based rendering instead? This is the slowest rendering technique but looks simpler than the other approaches.
User avatar
Dwedit
Posts: 4922
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Sprite 0 hit test corrupts my PPU

Post by Dwedit »

I haven't written such a PPU yet, but my design would be to only perform rendering at times when the CPU and PPU need to be synchronized.

Examples of times when the CPU and PPU need synchronization:
CPU affects what PPU draws:
* Scrolling
* CHR Bankswitching
* PPU control bit changes
* PPU mask bit changes
* Reaching the bottom of the screen (Just so it can finish drawing the frame)
PPU affects what CPU sees:
* Sprite 0 hit (Reaching the first colliding pixel)
* PPU triggered interrupts (such as MMC3)
* Reaching the time of the sprite overflow flag being set (Rarely used)
* Vblank happening (Trigger NMI, vblank flag, etc...)

This design allows you run the CPU and PPU mostly independently. The PPU can run from one "Old position" to a "New Position", for X number of dots (which may span multiple scanlines).
When you can run multiple dots, you can use whatever method you want to use to draw those dots. The dots could span whole scanlines, or even whole 8 scanline groups for rendering full square tiles.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
monterey755
Posts: 2
Joined: Sat Jun 19, 2021 3:16 am

Re: Sprite 0 hit test corrupts my PPU

Post by monterey755 »

It turns out that I forgot to clear the vblank flag after it is read and now the test rooms worked fine. Super Arabian is still corrupting my PPU though.

I'm definitely going to try your design, thanks.
Post Reply