

The Tricky-to-emulate games lists mentions, "Micro Machines requires correct values when reading PPU $2004 (OAMDATA) during rendering." What does this refer to exactly?


I carefully implemented that logic (see here), but I'm still getting the Micro Machines glitches. Did I miss something on that page?James wrote:It's referring to the behavior of $2004 reads during visible scanlines described here: http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation
Code: Select all
if (rendering)
{
if (current_cycle < 64)
return_value = 0xFF;
else if (current_cycle < 256)
return_value = 0x00;
else if (current_cycle < 320)
return_value = 0xFF;
else
return_value = sprite_buffer[0];
}
Code: Select all
...
FD6E: BIT $2004
FD71: BMI $FD73
FD73: PHA
...
Micro Machines reads $2004 around dot 320. If the read occurs before dot 320, it needs to see a value with the high bit set (implemented properly, the read would return $FF because it would take place while the PPU is fetching from an empty sprite slot). If the read occurs >= dot 320, it needs to see a value without the high bit set (which it does, because the first byte in secondary OAM is < 0x80).zeroone wrote:What's the concept behind the hack?
Yep. Implement it as described on the wiki.Is there an accurate way to do this?
I implemented as close to the wiki description as I could, but I must be misinterpreting something.James wrote:Yep. Implement it as described on the wiki.
I see the wiki says:James wrote:implemented properly, the read would return $FF because it would take place while the PPU is fetching from an empty sprite slot
Cycles 1-64: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF.
You also seem to be implying that $2004 returns the contents of secondary OAM. What address/offset into secondary OAM is accessed (if it is accessed)?James wrote:If the read occurs >= dot 320, it needs to see a value without the high bit set (which it does, because the first byte in secondary OAM is < 0x80).
$2004 reads return the contents of secondary OAM during these phases:zeroone wrote:Does that mean that $2004 returns the contents of secondary OAM?...You also seem to be implying that $2004 returns the contents of secondary OAM. What address/offset into secondary OAM is accessed (if it is accessed)?
wiki wrote: Cycles 257-320: Sprite fetches (8 sprites total, 8 cycles per sprite)
1-4: Read the Y-coordinate, tile number, attributes, and X-coordinate of the selected sprite from secondary OAM
5-8: Read the X-coordinate of the selected sprite from secondary OAM 4 times (while the PPU fetches the sprite tile data)
For the first empty sprite slot, this will consist of sprite #63's Y-coordinate followed by 3 $FF bytes; for subsequent empty sprite slots, this will be four $FF bytes
Cycles 321-340+0: Background render pipeline initialization
Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline)
$2004 reads at that time will expose what's happening during sprite eval. If you're referring to my code, it's not accurate behavior.zeroone wrote:Why will $2004 return 0 between PPU cycles 64 and 256?
What address of secondary OAM does it return?James wrote:$2004 reads return the contents of secondary OAM during these phases
By returning what exactly?James wrote:$2004 reads at that time will expose what's happening during sprite eval.
Code: Select all
int __fastcall Read4 (void)
{
if (IsRendering)
readLatch = Sprite[SpritePtr];
else readLatch = Sprite[SprAddr];
return readLatch;
}Can someone please provide more information? The wiki seems incomplete.Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this. It used to be thought that reading from this register wasn't reliable, however more recent evidence seems to suggest that this is solely due to corruption by OAMADDR writes. In the oldest instantiations of the PPU, as found on earlier Famicoms, this register is not readable. It's not known exactly which revision of the 2C02 added the readability—it is certainly absent in the RP2C02C, and present by the RP2C02G.


Can you elaborate on this?If the rendering is disabled and the PPU address is between $3F00-$3F1F, that's the color it outputs.