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:
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?
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
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
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?