It is currently Wed Oct 18, 2017 11:42 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Fri Jul 08, 2011 10:46 am 
Offline

Joined: Sat May 08, 2010 9:31 am
Posts: 225
Testing my new MMC1 implementation, I found some problems with "Dusty Diamond's All-Star Softball (U) [!]. nes". After the initial choices the rom hangs in an infinite loop. Tested with other emulators I noticed that there are the same problem. I understood what was the problem and now I know what you think. The rom does something like this:
1) writes 0x00 in $2003
2) writes 4 bytes in the OAM through the $2004 (setting sprite 0)
3) in the next video frame update the entire OAM using $4014 starting to write, however, from the the sprite 1 instead of 0.
In this way, the sprite 0 will always have a Y coordinate "0xFF" and then never gets hit and the game goes into an infinite loop waiting that bit 6 of $2002 is set.
It seems that before the writing of the $4014, the $2003 should be cleaned.
Following this logic, I tried to reset the $2003 at scanline 238 after the last evaluated sprite and the games started to work.
They also started to run even the chinese MMC3 rom that not working properly such as:
Aladdin 2 (Unl). Nes
Bing Kuang Ji Dan Zi - flighty Chicken (Ch). Nes
and many others


Top
 Profile  
 
PostPosted: Fri Jul 08, 2011 12:48 pm 
Offline
NESICIDE developer
User avatar

Joined: Mon Oct 13, 2008 7:55 pm
Posts: 1026
Location: Minneapolis, MN
Doesn't the OAM address get reset by the PPU somewhere in each scanline? I thought it used it during the sprite evaluation process which happens during pixels 0-255?


Top
 Profile  
 
PostPosted: Fri Jul 08, 2011 6:59 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3064
Location: Brazil
FHorse wrote:
It seems that before the writing of the $4014, the $2003 should be cleaned. Following this logic, I tried to reset the $2003 at scanline 238 after the last evaluated sprite and the games started to work.


Interesting. Cleaning the sprite address ($2003) before the VBlank was already discussed, but nobody got a definitive "yes" or a definitive "no".

There's something regarding using the upper $2003 bits to write sprites #0 and #1 data, but I'm unsure of it.

EDIT: here's the old discussion (sort of).

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 09, 2011 5:24 am 
Offline
User avatar

Joined: Sat Jan 22, 2005 8:51 am
Posts: 427
Location: Chicago, IL
These games work with nemulator; I never reset $2003.

_________________
get nemulator
http://nemulator.com


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 09, 2011 11:53 am 
Offline

Joined: Mon Sep 27, 2004 2:57 pm
Posts: 1248
Just purely incidentally, after reading this, I ran across this page on the wiki, which mentions $2003 being cleared.

I guess there's still some controversy as to how $2003 behaves during rendering?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 9:54 am 
Offline
User avatar

Joined: Sat Oct 29, 2005 2:09 am
Posts: 500
Location: Indianapolis
Drag wrote:
Just purely incidentally, after reading this, I ran across this page on the wiki, which mentions $2003 being cleared.

I guess there's still some controversy as to how $2003 behaves during rendering?


I discovered this long ago and thought it was well known... guess not? I clear it at the end of rendering on scanline 239. There are a few games that rely on this or else there's some subtle sprite errors.

I cannot remember which game it is now, but one game does strange stuff to 2003 so that sprite 0 is moved around (i.e. OAM entry 0 is NOT sprite 0). Huge Insect does this too. This is why it does not work on many emulators. The symptoms are the game starts fine, and the game screen works and everything... but no insects ever show up. This is because sprite 0 never hits, and that is caused by sachen "moving" sprite 0 by writing something to 2003 before sprite DMA'ing from what I recall.

The other game I'm thinking of (but unfortunately cannot remember the name of) does this too, but the game still works fine if you do not implement this. The problem is many sprites disappear due to them having more than 8 on a scanline. They did it to cycle the sprites without actually moving around the OAM entries like most other games did.

It appears that whatever sprite 2003 is pointing at will be sprite 0 as far as the rendering hardware is concerned. Since 2003 is reset at the end of rendering (or thereabouts), it usually is OAM entry 0. I do not know what happens if you set a non-MOD 4 value into 2003 before rendering though. i.e. if you load 01h 02h, or 03h into 2003. It's possible that the lower 2 bits are cleared before evaluation occurs but I don't know.

The actual OAM counter is composed of TWO separate counters on the PPU. The lower 2 bits is one counter, and the upper 6 are another counter. This is known because of how the OAM sprite overflow flag bug works. The state machine accidentally increments both counters at the same time instead of just the upper one after 8 sprites are rendered.

_________________
/* this is a comment */


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 12:18 pm 
Offline
User avatar

Joined: Sat Jan 22, 2005 8:51 am
Posts: 427
Location: Chicago, IL
kevtris wrote:
Huge Insect does this too. This is why it does not work on many emulators. The symptoms are the game starts fine, and the game screen works and everything... but no insects ever show up.

Huge Insect works fine on nemulator too. I wonder if I'm doing something else incorrectly...

_________________
get nemulator
http://nemulator.com


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 7:00 pm 
Online
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2962
Location: Tampere, Finland
The OAM address does get cleared *somewhere*, so it seems that the myth is a myth. I'm not sure if it's at the end of the scanline, or at the end of the frame, but here's a simple test I wrote:

Code:
#include <knes.h>

#pragma bss-name(push, "ZEROPAGE")
#pragma data-name(push, "ZEROPAGE")

void hang(void)
{
    while ( 1 );
}

const char* text;
void write_text(void)
{
    poll_vblank();
    // Just to make sure the writes won't occur outside vblank...
    PPU.mask = BGREND_OFF;
    // Copy the text to $21C4.
    PPU_ADDR( 0x21C4 );
    while ( *text )
    {
        PPU.data = *text++;
    }
    // Hopefully we're still in vblank. :)
    PPU_SCROLL( 0, 0 );
    PPU.mask = BGREND_ON;
}

byte hexnum;
void write_hexnum(void)
{
    static const char* hex_lut = "0123456789ABCDEF";
   
    poll_vblank();
    // Just to make sure the writes won't occur outside vblank...
    PPU.mask = BGREND_OFF;
    // Copy the text to $21E4.
    PPU_ADDR( 0x21E4 );
    PPU.data = hex_lut[ hexnum >> 4  ];
    PPU.data = hex_lut[ hexnum & 0xF ];
    // Hopefully we're still in vblank. :)
    PPU_SCROLL( 0, 0 );
    PPU.mask = BGREND_ON;
}

void set_palette(void)
{
    // Palette is initially initialized to black by KNES.

    poll_vblank();
   
    // Set the second palette color to white.
    PPU_ADDR( PPU_BG_PALETTE + 1 );
    PPU.data = 0x30; // White
}

void test1(void)
{
    // Test #1:
    //   Test if $2003 is cleared at the end of the frame.
   
    // Disable rendering.
    PPU.mask = 0;
   
    // Initialize the OAM to numbers 0-255.
    {
        byte i = 0;
        byte *p = ( byte * )OAM;
        do
        {
            *p++ = i;
        }
        while ( ++i != 0 );
        poll_vblank();
        OAM_DMA();
    }
   
    // Set the OAM address.
    poll_vblank();
    PPU.oam_addr = 0x4;
   
    // Enable rendering.
    PPU.mask = BGREND_ON;
   
    // Wait for the vblank (assuming the flag gets cleared during the frame).
    poll_vblank();
   
    // If the hypothesis is true, $2003 should now be 0.
    // We can determine the value by reading from OAM.
    hexnum = PPU.oam_data; write_hexnum();
   
    text = "TEST 1 READY"; write_text();
}

int main(void)
{
    set_palette();
   
    text = "READY"; write_text();
   
    test1();
   
    // Wait for the judgement day.
    hang();
   
    return 0;
}


ROM: http://kkfos.aspekt.fi/downloads/2003-test.zip

Correct output (based on my PAL NES) is:
Code:
TEST 1 READY
00


Nintendulator prints "04", Nestopia prints "00" and FCEUX prints "88" (doesn't support OAM readback?)

EDIT: Forgot to initialize "i" to 0 in the OAM init code, however this shouldn't change the behaviour because the reset code initializes the RAM.


Last edited by thefox on Mon Jul 11, 2011 11:16 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 7:12 pm 
Offline
NESICIDE developer
User avatar

Joined: Mon Oct 13, 2008 7:55 pm
Posts: 1026
Location: Minneapolis, MN
thefox wrote:
ROM: http://kkfos.aspekt.fi/downloads/2003-test.zip

Correct output (based on my PAL NES) is:
Code:
TEST 1 READY
00



Weird, this is what I get too, yet I hang at the Akira(J) Start/Continue screen and I don't get any insects in Huge Insect (I waited at least five minutes for one to show up).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 7:24 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3064
Location: Brazil
RockNES prints 04 too.

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 9:06 pm 
Online
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2962
Location: Tampere, Finland
I also forgot that OAM data readback isn't reliable, however this shouldn't matter on PAL NES as the OAM bytes 0-31 seem to be stable (based on blargg's earlier tests). It might produce strange results on NTSC NES though, depending on CPU-PPU synchronization. Can anybody try it out?

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2011 11:09 pm 
Online
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2962
Location: Tampere, Finland
I'm getting some *very* strange results when testing this on my PAL NES. Remember that PAL VBL is 70 scanlines long.

If I write a value to OAM addr, and read back (using $2004) during the first ~20 or so scanlines of the vblank, it returns the expected value. However, if I read after that point, the OAM addr seems to have changed (and the value depends on how many cycles after that point I read it). It's almost as if the PAL PPU starts evaluating sprites while still in vblank?

Also in the test I posted earlier, if I change the oam_addr init value to something like 0x69, it ends up as 0x80 after the end of the frame instead of 0. So it seems to be incorrect to say (per se) that the OAM addr is cleared at some point in the frame. It's more likely that it gets cleared (under some conditions only!) as a result of the scanline sprite evaluation logic (which uses the same register).

Take this with a grain of salt, there are so many factors in play (like OAM readback corruption) that it's easy to make mistakes. I need to run some more tests later. And finally get me an NTSC NES.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 19, 2011 1:14 am 
Online
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2962
Location: Tampere, Finland
thefox wrote:
If I write a value to OAM addr, and read back (using $2004) during the first ~20 or so scanlines of the vblank, it returns the expected value. However, if I read after that point, the OAM addr seems to have changed (and the value depends on how many cycles after that point I read it). It's almost as if the PAL PPU starts evaluating sprites while still in vblank?

I've confirmed this. Doing OAM DMA on PAL NES more than ~20 or so (didn't time this exactly) scanlines into vblank will *not* copy the sprites over properly.

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


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 19, 2011 5:08 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19096
Location: NE Indiana, USA (NTSC)
So it might not be 70 lines of vblank and 1 line of pre-render as much as 20 lines of vblank and 51 lines of pre-render. Does this newly discovered OAM copy failure also happen if you have forced blank on?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 19, 2011 5:43 am 
Online
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2962
Location: Tampere, Finland
tepples wrote:
Does this newly discovered OAM copy failure also happen if you have forced blank on?

Yes.

Quote:
Also in the test I posted earlier, if I change the oam_addr init value to something like 0x69, it ends up as 0x80 after the end of the frame instead of 0.

This I couldn't reproduce for whatever reason. Strange.


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

All times are UTC - 7 hours


Who is online

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