It is currently Sat Dec 16, 2017 1:37 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Fri May 28, 2010 6:35 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I've found some very weird OAM read behavior on my NTSC NES, and I'm pretty sure it occurs on the PAL one as well (I know it also acts weird, just haven't swapped boards back to try it yet). Basically, reading from OAM is broken for three out of the four PPU-CPU synchronizations that the system will be in after power or reset. I've been tearing my hair out trying to make sense of this, thinking my NTSC NES was damaged. Once I realized it was related to PPU-CPU synchronization, and that there were exactly four possible patterns of behavior, it started falling into place.

When SPRDATA reads are working correctly, they give you the contents of OAM at whatever SPRADDR is set to. When they're not, some/many/most addresses give you OAM at a different address. I haven't tested writing thoroughly, but I'm pretty sure that SPRDATA writes and SPRDMA work reliably all the time, explaining why this crazy behavior wouldn't have been a problem, as SPRDATA reads are rarely/never used.

I wrote a test program to determine what OAM byte is actually read for each address. It tries them from $00-$FF, with 16 per row. So when working correctly, we'd expect it to begin

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
...

But let's say it's all correct as above, except that reading from address $04 really reads from $48:

00 01 02 03 48 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
...

Since it's difficult to easily see the incorrect entry, the test program prints -- for correct entries, so for the second example above, it prints

-- -- -- -- 48 -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
...

So, here are the three insane mappings I get, randomly chosen at reset, but unchanging until I reset/power again:
Code:
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
18 19 1A 1B 1C 1D 1E 1F -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
-- -- -- -- -- -- -- -- 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27
20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27

-- 21 22 23 24 25 26 27 -- 21 22 23 24 25 26 27
-- 21 22 23 24 25 26 27 -- 21 22 23 24 25 26 27
-- -- -- -- -- -- -- -- 20 21 22 23 24 25 26 27
-- 21 22 23 24 25 26 27 -- 21 22 23 24 25 26 27
-- 21 22 23 24 25 26 27 -- 29 2A 23 2C 25 26 27
-- 21 22 23 24 25 26 27 -- 39 0A 23 2C 25 26 27
-- -- -- -- -- -- -- -- -- 61 62 63 64 65 66 67
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
-- -- 82 -- -- -- 26 A7 -- -- -- -- -- 8D 0E AF
-- -- -- -- -- 25 26 27 -- A1 A2 A3 A4 25 26 27
-- A1 A2 A3 A4 25 26 27 -- -- -- -- -- -- AE AF
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

The first two are stable. The first one simply reads $18-$1F when $20-$27 are read, nice and simple. The second one mirrors $20-$27 over the entire range! The last one is unstable, where the mappings change somewhat randomly, but still follow the above general pattern.

I'll probably be working more on this tomorrow, hopefully making the test program standalone so others can see how their NES behaves (I imagine each will be slightly different). Any thoughts on it?


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 28, 2010 7:25 pm 
Offline

Joined: Thu Oct 27, 2005 1:44 pm
Posts: 449
Location: CA
This isn't at all helpful, but wasn't there at least one production game that read back OAM? Micro Machines? Maybe it just wrote OAM mid frame?

I would be interested in a test app. Will be interesting to see what clones do too. Would there be a separate way to identify which clock alignment is running, other than looking at the mapping results?


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 29, 2010 4:03 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19351
Location: NE Indiana, USA (NTSC)
This could be related to the refresh bug I helped discover that caused pieces to flicker in LJ65. The working hypothesis was that there is an uncompleted 8-byte DRAM refresh transaction in the PPU's internal buffer, which gets sprayed somewhere else if you do "funny" things. Try displaying at least one full frame with rendering turned on before you fill and then read back OAM.


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 29, 2010 5:34 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I'm getting a feeling that OAM was never meant to be read, that the read functionality was meant exactly for what Micro Machines does. That would explain why reading doesn't increment the address (so it wouldn't disturb when you read while PPU rendering is occurring). Still probing this behavior, right now writing a program to see whether OAM even works as expected on the one PPU-CPU alignment that seems normal.


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 29, 2010 10:40 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
tepples: enabling sprite rendering beforehand didn't seem to have any effect. This seems to be entirely based on the PPU-CPU synchronization. It'll be interesting to see how this behaves on PAL, now that I've got the cause figured out.

Here's a test ROM that visually shows what addresses don't read back normally (full ca65 source included):

oam_read.zip

It tests OAM reading ($2004), being sure it reads the byte from OAM at the current address in $2003. It scans OAM from 0 to $FF, testing each byte in sequence. It prints a '-' where it reads back from the current address, and '*' where it doesn't. Each row represents 16 bytes of OAM, 16 rows total.

On my NTSC front-loader NES, I get the following four general patterns at random after power/reset:

Image

I also wrote another test that thoroughly tests OAM:

oam_stress.zip

It randomly sets the address, then randomly either writes a random number of random bytes, or reads from the current address a random number of times and verifies that it matches what's expected. It does this for tens of seconds (refreshing OAM periodically so it doesn't fade). Once done, it verifies that all bytes in OAM match what's expected. This only passes for the left-hand pattern above. It also prints a pattern, but it's just based on what it's modified so far, so it might not exactly match the pattern from the first test.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 30, 2010 11:08 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2983
Location: Tampere, Finland
I would've tried this on my PAL NES but couldn't get my piece of shit toasters to work. Gave up after 15 minutes of cycling power and adjusting the cart. I'm very interested in the results for PAL though.

I guess this would also explain why sprites were sometimes corrupted in some games when using my PowerPak save state mappers.

BTW oam_stress fails in Nintendulator, I wonder why?

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 30, 2010 1:23 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I realized that having these tests fail isn't correct, since they should never fail on a NES. The system under test is merely failing to meet our desirable simple model of behavior.

How quickly does Nintendulator fail? That's surprising.

bunnyboy, sorry I ignored one of your questions. Yes, it's possible to determine the PPU-CPU synchronization separately from these tests. I did so and verified that each pattern corresponds to a particular synchronization. Or are you requesting a ROM to test that via the other means (VBL timing, sprite hit, overflow)?


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 30, 2010 1:27 pm 
Offline

Joined: Thu Oct 07, 2004 2:47 am
Posts: 42
I tested oam_read on a PAL NES and famicom and got the following results:

PAL NES
Most of the reads on lines 3-8 always failed, it never passed completely. The errors started from midway on line 3 and ended on beginning of line 8, and all other lines passed without errors. The exact patterns on these lines was random each time after reset. So nothing like the NTSC results, and I'd test on my other PAL unit also but the controller port is broken. Would be interesting to see if it behaves similar or is completely random.

Famicom
The famicom always failed on all reads every time, seems like sprite reads doesn't work at all.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 30, 2010 2:36 pm 
Offline
User avatar

Joined: Mon Nov 27, 2006 11:56 pm
Posts: 86
Location: Sollentuna, Sweden
blargg wrote:
I'm getting a feeling that OAM was never meant to be read, that the read functionality was meant exactly for what Micro Machines does.


What exacly is it that Micro Machines does?


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 30, 2010 3:05 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Very interesting that Famicom fails all the time. I'll have to write a test for you to run to see what exactly $2004 returns.

I still need to go back to PAL testing (it's tedious because all I have is a PAL nes board, but no case, so I have to pull my NTSC NES apart and put the PAL board in and hook everything up to it). I was seeing what you mentioned before, where they work except a certain part of the frame. I'm guessing that it's because the PPU-CPU synchronization on PAL constantly drifts around, rather than being frozen at power/reset as on NTSC.

Micro Machines is covered in previous posts. I'm not sure of the details. In one thread Disch and I discussed this and came up with some code to reliably use it in place of sprite #0 hit.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 01, 2010 5:23 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2983
Location: Tampere, Finland
blargg wrote:
How quickly does Nintendulator fail? That's surprising.

Very quickly.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 01, 2010 7:27 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I had JSR run a further test on the Famicom and it seems that reading from $2004 is like reading from any other write-only PPU register, at least when rendering is disabled. We're going to see whether it behaves any differently when rendering is enabled.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 01, 2010 7:35 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
So that scanline detection method based on $2004 reads is history, right?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 01, 2010 8:44 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
We have yet to see what $2004 reads back with rendering enabled on a Famicom. I also haven't tested that technique on my NTSC NES with the various PPU synchronizations. I'm betting it'll work fine on NTSC, that $2004 reading exists for this very purpose.

EDIT: Jsr pretty well verified that $2004 is a write-only register on Famicom in all cases, so yeah, I guess the $2004 read during rendering approach to scanline synchronization is dead, at least if you want Famicom compatibility.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 07, 2010 6:07 am 
Offline

Joined: Sun Dec 07, 2008 1:11 pm
Posts: 92
blargg wrote:
Very interesting that Famicom fails all the time.


On the Famicom, both PPU and CPU are connected to the reset circuit/switch, which implies that there might be no variations in cycle alignment at all on this system, since every reset brings both PPU and CPU in a defined state. On the NES, the PPU reset line is tied to VCC (deactivated), hence the picture stays stable when pushing reset, unlike the Famicom.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 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