I've implemented accurate PPU/CPU timing in my emulator. Some people call it a tile renderer--that is, it renders a tile (or does a single batch of PPU fetches), then updates the CPU, and so on and so forth. However, once I had implemented this, it really sent my sprite zero collision timing off (the word "collision" makes more sense than hit, I believe, as it's only set when sprite zero "collides" with a non-transparent background pixel). I was using the following algorithm, used in many current nes emulators such as nofrendo and fakenes, to compute the number of cycles until the sprite collision flag in the ppu status register would be set:
sprite_hit_cycles = get_cycles_left_this_frame() - (screen_x_coordinate_of_collision * cpu_cycles_per_pixel);
if (get_cycles_left_this_frame() < sprite_hit_cycles)
Now, I take into account any precision lost in converting between ppu and cpu cycles (I have it set up to use either 24:8 fixed point or 32-bit floating point math). The number of cycles left in the frame is also updated each execution of cycles, so it's not as if it's a bug with executing a cpu instruction or two (or none in some cases) per tile. No, clearly, the real PPU doesn't set the sprite collision flag at the pixel, not even with a slight delay.
In order to get super mario bros. working correctly, I had to add an 81 PIXEL DELAY to (screen_x_coordinate_of_collision * cpu_cycles_per_pixel) before subtracting it from the number of cycles left. Any less of a delay, and the bottom row of the the status screen (the "x00 1-1" part) would flicker.
Here's a screen shot of Super Mario Bros. from my emulator so you know what I mean when I say the bottom row of "x00 1-1".
Now the actual delay could be much more in reality. Perhaps the sprite collision flag actually isn't set until the end of the line? Most other emulators don't seem to have this problem as the cpu doesn't execute anymore instructions until the end of the line anyway.
Or perhaps it's completely something different? Any thoughts?
P.S. Yeah, that's a real screen shot from my emulator with a little code snippet of the accurate scan line "per-tile" emulation code.
P.P.S. Yes it gets a nice frame rate, it's not too slow at all.
P.P.P.S If you look closely, the graphics are bilinearly filtered. I use Direct3D8 to accomplish this, and hope to add an OpenGL graphics driver later.
P.P.P.P.S No that image is not doctored in anyway. ;)
- Jesse "The Code Demon" Towner