nesdev.com
http://forums.nesdev.com/

Micro Machines glitches
http://forums.nesdev.com/viewtopic.php?f=3&t=12425
Page 1 of 6

Author:  zeroone [ Tue Feb 24, 2015 9:22 am ]
Post subject:  Micro Machines glitches

Shaky horizontal lines appear on the right-side of some of the screens of Micro Machines in my emulator. The game itself seems to play okay though.

Image

Image

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?

Author:  James [ Tue Feb 24, 2015 10:32 am ]
Post subject:  Re: Micro Machines glitches

It's referring to the behavior of $2004 reads during visible scanlines described here: http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation

Author:  zeroone [ Tue Feb 24, 2015 11:29 am ]
Post subject:  Re: Micro Machines glitches

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


I carefully implemented that logic (see here), but I'm still getting the Micro Machines glitches. Did I miss something on that page?

Author:  zeroone [ Tue Feb 24, 2015 12:05 pm ]
Post subject:  Re: Micro Machines glitches

Wait a second. I downloaded a different ROM and this one wants to use mapper 71 instead of mapper 2. WTF?

I'll implement that mapper and see what happens...

Edit: Unfortunately, implementing mapper 71 did not help. The graphical glitches still look the same.

Author:  James [ Tue Feb 24, 2015 12:58 pm ]
Post subject:  Re: Micro Machines glitches

re: mapper 2 vs. 71: http://wiki.nesdev.com/w/index.php/INES_Mapper_071

As far as $2004 reads go, this (hack) should be enough to make Micro Machines work:

Code:
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];
}


I don't completely understand what the game is doing here, but it seems that the whole purpose of these reads is to adjust timing:

Code:
...
FD6E:   BIT $2004
FD71:   BMI $FD73
FD73:   PHA
...


The only impact that BMI can have is on the number of clock cycles consumed, so make sure that you're accounting for the extra clock cycle on a taken branch.

Author:  zeroone [ Tue Feb 24, 2015 1:29 pm ]
Post subject:  Re: Micro Machines glitches

Thanks. That did not solve the problem, but it did have a noticeable effect. It reduced the amount of glitching.

What's the concept behind the hack? Is there an accurate way to do this?

Author:  James [ Tue Feb 24, 2015 3:03 pm ]
Post subject:  Re: Micro Machines glitches

zeroone wrote:
What's the concept behind the hack?

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).

Quote:
Is there an accurate way to do this?

Yep. Implement it as described on the wiki.

Author:  zeroone [ Tue Feb 24, 2015 3:41 pm ]
Post subject:  Re: Micro Machines glitches

James, thanks for the reply.

James wrote:
Yep. Implement it as described on the wiki.


I implemented as close to the wiki description as I could, but I must be misinterpreting something.

James wrote:
implemented properly, the read would return $FF because it would take place while the PPU is fetching from an empty sprite slot


I see the wiki says:

Quote:
Cycles 1-64: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF.


Does that mean that $2004 returns the contents of secondary OAM?

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).


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

Why will $2004 return 0 between PPU cycles 64 and 256?

Author:  James [ Tue Feb 24, 2015 4:14 pm ]
Post subject:  Re: Micro Machines glitches

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

$2004 reads return the contents of secondary OAM during these phases:
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)

zeroone wrote:
Why will $2004 return 0 between PPU cycles 64 and 256?

$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.

Somebody who has implemented proper sprite eval logic can probably explain it better.

Oh, one more thing: I'm using the "old" PPU cycle terminology: e.g., idle cycle = 340, not 0, so adjust accordingly if you're not.

Author:  zeroone [ Tue Feb 24, 2015 4:40 pm ]
Post subject:  Re: Micro Machines glitches

James wrote:
$2004 reads return the contents of secondary OAM during these phases


What address of secondary OAM does it return?

James wrote:
$2004 reads at that time will expose what's happening during sprite eval.


By returning what exactly?

Author:  zeroone [ Wed Feb 25, 2015 10:53 am ]
Post subject:  Re: Micro Machines glitches

Here is the $2004 read according to Nintendulator:

Code:
int   __fastcall   Read4 (void)
{
   if (IsRendering)
      readLatch = Sprite[SpritePtr];
   else   readLatch = Sprite[SprAddr];
   return readLatch;
}


The Sprite array appears to represent both primary and secondary OAM.

According to the wiki:

Quote:
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 someone please provide more information? The wiki seems incomplete.

Edit: On a side note, FCEUX 2.2.1 looks more screwed up than my emulator:

Image

Image

Author:  tokumaru [ Wed Feb 25, 2015 2:31 pm ]
Post subject:  Re: Micro Machines glitches

FCEUX is pretty bad at emulating these kinds of obscure quirks.

Author:  Zepper [ Wed Feb 25, 2015 2:35 pm ]
Post subject:  Re: Micro Machines glitches

If the rendering is disabled and the PPU address is between $3F00-$3F1F, that's the color it outputs.

Author:  zeroone [ Wed Feb 25, 2015 3:23 pm ]
Post subject:  Re: Micro Machines glitches

Quote:
If the rendering is disabled and the PPU address is between $3F00-$3F1F, that's the color it outputs.


Can you elaborate on this?

Author:  tepples [ Wed Feb 25, 2015 3:48 pm ]
Post subject:  Re: Micro Machines glitches

  • If rendering is disabled, and the current VRAM address is $0000-$3EFF, the PPU will output the color at $3F00.
  • If rendering is disabled, and the current VRAM address is $3F00, the PPU will output the color at $3F00.
  • If rendering is disabled, and the current VRAM address is $3F01, the PPU will output the color at $3F01.
  • If rendering is disabled, and the current VRAM address is $3F02, the PPU will output the color at $3F02.
  • If rendering is disabled, and the current VRAM address is $3F03, the PPU will output the color at $3F03.

It stores a table of colors at $3F00-$3F1F and expects to be able to switch to the next color by reading one byte from or writing one byte to the VRAM data port, which advances the VRAM address by 1.

Page 1 of 6 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/