PowerPak + Tetramino = sprite flicker

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderators: B00daW, Moderators

User avatar
Banshaku
Posts: 2328
Joined: Tue Jun 24, 2008 8:38 pm
Location: Fukuoka, Japan
Contact:

Post by Banshaku » Thu Dec 18, 2008 7:04 pm

I did more tests but without success. I guess I reached my limit regarding my current nes knowledge.

For now I know more about your code base than the nes so I cannot move forward with appropriate tests. It ether a more than 8 sprites bug or something related to blanking since a lot of processing is done there. You game seems to requires very precise timing and if you don't, the screen gets affected. If feels like a VSYNC bug on dos where the sync is not done properly and some part of the screen flickers. Don't know if DMA transfer could have any impact if done in specific conditions since it's related to sprite so. hmmm... But since I don't know enough, I cannot find a way to test it.

Sorry to have not been more useful than that. I hope you find it soon. If you do, I really want to know what you fixed.

tepples
Posts: 21746
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Thu Dec 18, 2008 7:34 pm

Banshaku wrote:You game seems to requires very precise timing
Is this Battletoads?
and if you don't, the screen gets affected. If feels like a VSYNC bug on dos where the sync is not done properly and some part of the screen flickers.
Well at least it flickers and doesn't crash due to the vblank_instead system. A lot of emu authors wish they could say the same for some Rare games.

Anyway, I have some ideas how I could redo the top of the playfield frame to fit under the 8 sprite limit. As for the flicker in the preview on the PowerPak, it seems to go away when a piece lands (but before it locks).

Drag
Posts: 1285
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Post by Drag » Sat Dec 20, 2008 8:18 pm

Is your program waiting the proper amount of time to allow the PPU to stablize on bootup, before writing to any PPU registers? This is the absolute only thing I can think of that would cause weird glitches on the hardware, where it wouldn't on emulators.

Then again, if this is the powerpak, it probably wouldn't matter... but it's all I've got. *shrugs*

tepples
Posts: 21746
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Sun Dec 21, 2008 7:33 pm

Drag wrote:Is your program waiting the proper amount of time to allow the PPU to stablize on bootup, before writing to any PPU registers?
Yes, and I assume the PowerPak BIOS is doing the same.

I've uploaded version 0.32, which changes how the falling piece is drawn to virtually eliminate the sprite dropout that caused problems even in emulation. Any remaining flicker is almost certainly a result of a poorly understood quirk of the NES or the PowerPak. Can I get some more testing done?

User avatar
Banshaku
Posts: 2328
Joined: Tue Jun 24, 2008 8:38 pm
Location: Fukuoka, Japan
Contact:

Post by Banshaku » Sun Dec 21, 2008 10:27 pm

tepples wrote:I've uploaded version 0.32, which changes how the falling piece is drawn to virtually eliminate the sprite dropout that caused problems even in emulation. Any remaining flicker is almost certainly a result of a poorly understood quirk of the NES or the PowerPak. Can I get some more testing done?
If I can find some time (since I have to re-edit it for MMC3), I will test it on my dev cart. I will see what I can do this week.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Mon Dec 22, 2008 3:49 am

tepples, I looked into this and (6 hours later) you were right about a new hardware quirk. Disabling rendering before the end of the frame indeed causes erratic behavior of sprite RAM on the next frame, regardless of whether you use DMA or manually copy bytes to it. It's not all bad, as I found a way to avoid it: disable rendering during pixels 66 to 254 (approximate), and ensure that any intersection with sprites is on their last row. If that scanline intersects a sprite's earlier rows, you get the erratic behavior no matter when you disable rendering. This means if you're using sprite hit for timing, you'll have to either settle for a visual glitch near the end of that scanline, or have the next scanline black and wait until its middle of before disabling rendering. There's no reasonable way to get the glitch right at the end of the scanline, because the timing variance when synchronizing to sprite hit is too great (around 21 pixels at best).

I think the following fixes things (I got the game running on my RAM devcart). Put sprite 0 at X=248, Y=223, and make it use tile $B1. Set tile $B1 to be a horizontal bar at the bottom (0,0,0,0,0,0,0,$FF). This way it collides on its last row. Also, insert a ~55-clock delay loop just before "BEGIN VRAM UPDATE" (you might be able to reduce the delay slightly).

I'll try to post my hardware test code soon.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Dec 22, 2008 1:28 pm

blargg wrote:tepples, I looked into this and (6 hours later) you were right about a new hardware quirk. Disabling rendering before the end of the frame indeed causes erratic behavior of sprite RAM on the next frame, regardless of whether you use DMA or manually copy bytes to it. It's not all bad, as I found a way to avoid it: disable rendering during pixels 66 to 254 (approximate), and ensure that any intersection with sprites is on their last row. If that scanline intersects a sprite's earlier rows, you get the erratic behavior no matter when you disable rendering. This means if you're using sprite hit for timing, you'll have to either settle for a visual glitch near the end of that scanline, or have the next scanline black and wait until its middle of before disabling rendering. There's no reasonable way to get the glitch right at the end of the scanline, because the timing variance when synchronizing to sprite hit is too great (around 21 pixels at best).
Sorry, it's kind of hard to follow what you're saying, so I may sound ridiculous. Are you saying that if you disable rendering, you have to disable it on a scanline that doesn't intersect a sprite unless it's the sprite's last row of pixels? Also, what kind of "erratic" behavior does this cause? Is it just flickering or complete unpredictability?

User avatar
tokumaru
Posts: 11465
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Mon Dec 22, 2008 4:15 pm

How do all the commercial games that disable rendering earlier work fine then?

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Mon Dec 22, 2008 6:59 pm

Celius wrote:Are you saying that if you disable rendering, you have to disable it on a scanline that doesn't intersect a sprite unless it's the sprite's last row of pixels? Also, what kind of "erratic" behavior does this cause? Is it just flickering or complete unpredictability?
Correct. The erratic behavior in my tests is a pair of sprites disappearing on the next frame. Which pair disappears can depend on which exact PPU clock rendering is disabled on. Since most games don't synchronize to exact PPU clocks, this means that a different pair of sprites will be affected each time, causing flickering (exactly what we see in Tetramino).
tokumaru wrote:How do all the commercial games that disable rendering earlier work fine then?
I don't know. Perhaps they avoid the conditions that cause the glitch, avoid using the particular sprites affected, or maybe they don't work fine, since the effect so far just seems to be some extra flicker on a few sprites.

Here's the ROM and ca65 source that demonstrate the issue. I imagine an examination of the PPU rendering steps during a scanline might shed light on the pattern of sprites affected.

sprite_bug.zip
Last edited by blargg on Mon Dec 22, 2008 7:01 pm, edited 1 time in total.

tepples
Posts: 21746
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Mon Dec 22, 2008 6:59 pm

I tried to hold back as much as I could on suggesting a new PPU quirk because only a bad workman rushes to blame his tools. It gave me a chance to improve the overall quality of control processing and sprite handling, to the point where I might even be able to add the ghost piece seen in newer Tetris products. Thank you, blargg, for figuring out what was really going on, helping me make the sprites 100% flicker-free on my PowerPak, and confirming that I am not a bad workman. You've got a credit in the change log of the forthcoming version 0.33.
tokumaru wrote:How do all the commercial games that disable rendering earlier work fine then?
I don't know. Perhaps I'm triggering a bug like the one that Andrew Davie's team triggered in early builds of The Three Stooges (OAM retention time decreases when some PPU revisions overheat). It just goes to show that there's a lot we still don't know about the PPU.
blargg wrote:I think the following fixes things (I got the game running on my RAM devcart). Put sprite 0 at X=248, Y=223, and make it use tile $B1. Set tile $B1 to be a horizontal bar at the bottom (0,0,0,0,0,0,0,$FF). This way it collides on its last row.
I already had a tile like that: tile $5F (ASCII for the underscore). I have been reserving $B0-$CF for a subtitle, like on the DreamEmulation CD.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Dec 22, 2008 7:36 pm

Well if it's only flickering, that's not the worst thing in the world. Actually, I kind of like the way sprite flickering looks; it characterizes NES games. I believe it was kyuusaku who was saying the same thing about attribute glitches, and I can see where he's coming from with that. If it doesn't cause RAM corruption where random values are just littered all over the sprite page, I guess it's alright. I was really worried because in my polygon sequence engine, I use a sprite zero hit to shut the screen off 40 scanlines early, spilling 40 scanlines out of Vblank, and I have sprites on screen with this engine. So this seems like a perfect candidate for the corruption.

There's probably tons we still don't know about the PPU. I can't imagine trying to find this bug though; I wouldn't have the slightest clue where to begin. Yes, thanks blargg for going through tedious crap to find yet another weird quirk with the NES :).

User avatar
Memblers
Site Admin
Posts: 3769
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Mon Dec 22, 2008 8:05 pm

The Garage Cart #1 intro turns the screen off mid-frame and does a 2nd sprite DMA. I do seem to remember a little bit of flickering on the 2nd part that apparently went away after I had adjusted the delay timing to fix something else. (The first part was mostly a dim starfield, so flickering could've been unnoticed or nicer).

I usually have been using a horizontal line for sprite #0, otherwise maybe I would've been stuck with that bug and never known why until now. I do know it's been said to do that, but I don't know where.

That's some quality obscure info. The PPU needs an errata sheet. :)

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Mon Dec 22, 2008 10:29 pm

OK, I've done some OAM memory examination and am making more sense of what happens. It looks like disabling rendering mid-scanline confuses the OAM refresh circuitry (at least I'm assuming it does refresh, being DRAM and all), so that when it runs at the beginning of the next frame, the first refresh writes to wherever it was when rendering was disabled. So if it was at sprite 20 before, it will copy the first two sprites over sprites 20 and 21 (apparently refresh is done in blocks of 8 bytes). I think I ran into this bug a while back, but never tracked it down. Hopefully I'll come across that code again and be able to verify it being the same thing. I've encountered similar bugs in the Game Boy hardware (DMG), where OAM and sound wave RAM can become corrupt in the same manner, with other parts duplicated.

Here's an example. Dashes every 4 bytes, for clarity. The first two sprites have different tile and attribute, to distinguish them, and the rest use tile and attribute 03.

Code: Select all

80 04 00 80-1A 05 01 8B-1A 03 03 96...80 04 00 80-1A 05 01 8B-46 03 03 80-46 03 03 8B-46 03 03 96-46 03 03 A1...
^^^^^^^^^^^^^^^^^^^^^^^               ^^^^^^^^^^^^^^^^^^^^^^^
80 04 00 80-1A 05 01 8B-1A 03 03 96...3B 03 03 96-3B 03 03 A1-80 04 00 80-1A 05 01 8B-46 03 03 96-46 03 03 A1...
^^^^^^^^^^^^^^^^^^^^^^^                                       ^^^^^^^^^^^^^^^^^^^^^^^
80 04 00 80-1A 05 01 8B-1A 03 03 96...3B 03 03 96-3B 03 03 A1-46 03 03 80-46 03 03 8B-80 04 00 80-1A 05 01 8B...
^^^^^^^^^^^^^^^^^^^^^^^                                                               ^^^^^^^^^^^^^^^^^^^^^^^
Each line is with the PPU disabled one PPU clock later than the previous. You can see how the first 8 bytes get duplicated in different locations based on that. This is what happens to sprite data written at the beginning of the frame after the one where PPU rendering was disabled early. I read it back after that frame was displayed. I get the corruption even if I just let that frame run for a few scanlines, the disable rendering and read it back immediately.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Dec 22, 2008 11:36 pm

If it leaves off on sprite 63, would it overwrite sprite #63 and sprite #0 with sprite #0 and #1? Again, sorry if that sounds ridiculous. I am still a little rough when it comes to the really technical things inside the PPU.

User avatar
dXtr
Posts: 375
Joined: Tue Sep 21, 2004 12:11 am
Location: Karlshamn (Sweden)

Post by dXtr » Tue Dec 23, 2008 5:29 am

tepples wrote:I tried to hold back as much as I could on suggesting a new PPU quirk because only a bad workman rushes to blame his tools.
But you should never hesitate to blame it when you can't find anything else being wrong ;)
I've blamed visual studio for a few problems in the past and found out that it actually was visual studios fault :)

One time it was a bad memory leak and after lots of debugging I discovered that it was a problem in the stream classes in STL shipped with the first version of VS.NET 2005.

Post Reply