It is currently Tue Sep 18, 2018 10:58 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 33 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Where to start DMA
PostPosted: Mon Apr 10, 2006 9:31 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
Logic tells me that $4014 would start copying data from the given address and putting it in OAM, starting at the sprite address specified by $2003. For example:

Code:
LDA #$80
STA $2003
LDA #$02
STA $4014


That would copy $0200->OAM[$80], $0201->OAM[$81], etc

However various games give me trouble when emulating like this -- and I find I have to start DMA at OAM[0], REGARDLESS of the sprite address. In my most recent example.... Akira (J) does the following:

Code:
C130:  A2 00      LDX  #$00                30 20 10  [..I.C]  FD
C132:  8E 03 20   STX  $2003    [2003=BA]  30 00 10  [..IZC]  FD
C135:  BD DA C1   LDA  $C1DA,X  [C1DA=7F]  30 00 10  [..IZC]  FD
C138:  8D 04 20   STA  $2004    [2004=BA]  7F 00 10  [..I.C]  FD
C13B:  E8         INX                      7F 00 10  [..I.C]  FD
C13C:  E0 04      CPX  #$04                7F 01 10  [..I.C]  FD
C13E:  90 F5      BCC  $F5         [C135]  7F 01 10  [N.I..]  FD
C135:  BD DA C1   LDA  $C1DA,X  [C1DB=81]  7F 01 10  [N.I..]  FD
C138:  8D 04 20   STA  $2004    [2004=BA]  81 01 10  [N.I..]  FD
C13B:  E8         INX                      81 01 10  [N.I..]  FD
C13C:  E0 04      CPX  #$04                81 02 10  [..I..]  FD
C13E:  90 F5      BCC  $F5         [C135]  81 02 10  [N.I..]  FD
C135:  BD DA C1   LDA  $C1DA,X  [C1DC=21]  81 02 10  [N.I..]  FD
C138:  8D 04 20   STA  $2004    [2004=BA]  21 02 10  [..I..]  FD
C13B:  E8         INX                      21 02 10  [..I..]  FD
C13C:  E0 04      CPX  #$04                21 03 10  [..I..]  FD
C13E:  90 F5      BCC  $F5         [C135]  21 03 10  [N.I..]  FD
C135:  BD DA C1   LDA  $C1DA,X  [C1DD=F0]  21 03 10  [N.I..]  FD
C138:  8D 04 20   STA  $2004    [2004=BA]  F0 03 10  [N.I..]  FD


After that code, the game writes to $4014 some time later -- however between the above code and the DMA, there is no further writes to $2003 or $2004. That above code leaves the sprite address at $04, so my emu currently is copying sprite data starting at OAM[4] (making sprite 0 use the last 4 bytes copied instead of the first 4).

Of course... this is causing sprite 0 to never be rendered, and the game falls into an infinite wait-for-sprite-0-hit loop afterwards.

Any clarification on this? Does the DMA write $00 to $2003 before copying bytes (perhaps that's why it takes 513 cycles instead of 512)? Or does the DMA just ignore the sprite address completely (seems less likely)? Or is there some other reason behind this?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 9:57 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20552
Location: NE Indiana, USA (NTSC)
How many CPU cycles elapse between the last write to $2003/$2004 and the writes to $4014?
Perhaps the OAM destination address, like OAM itself, is DRAM that leaks down to $00.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 10:08 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
Between the last $2004 write and the next $4014 write, it's about 5 scanlines.

There are 5 $4014 writes total after the $2004 write (one every frame)... then the game gets stuck.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 10:41 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
My misc PPU test ROMs one tests sprite DMA and shows that the value in $2003 is used, and left intact after DMA (since it copies 256 bytes). In my emulator I clear $2003 at the beginning of VBL and am pretty sure I found this to be the case on the NES. Where in the frame does this trace occur?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 11:04 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
The $2003 write occurs around cycle 279 of scanline 234 (where 0-239 are rendered scanline)

The PPU is off at the time the above code is run.

In game -- the hang happens after you press Start at the title screen (Start/Continue)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 12:19 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
I tried Akira (J) (after quickly implementing its mapper) and it hangs when I don't have my PPU clear $2003 at the beginning of VBL. Based on the timing you stated, 5 scanlines would put the $4014 write just after VBL where $2003 is cleared. What am I missing?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 12:29 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
Is it possible that screen rendering messes with $2003? Perhaps the PPU changes it as it fetches sprite data from OAM for rendering, and by the end of the frame it's found its way back to $00?

</wild guess>


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 1:57 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Quote:
Is it possible that screen rendering messes with $2003? Perhaps the PPU changes it as it fetches sprite data from OAM for rendering, and by the end of the frame it's found its way back to $00?


Looks to be the case. PPU rendering disabled for several frames, $2003 unchanged. Enabling rendering at VBL+29544 (scanline 259, 316 PPU clocks) then disabling causes sprite address to become zero. Enabling rendering one CPU clock later leaves sprite address unaffected. Also enabling then disabling before the end of the frame leaves various values in the sprite address (not shown).

Code:
lda  #0
sta  $2001

lda  #$EA
sta  $2003
jsr  sync_ppu_20    ; after return, time = VBL-20
ldy  #140           ; 29559 delay
lda  #41       
jsr  delay_ya2
lda  #$18
sta  $2001          ; writes at VBL+29544
lda  #0
sta  $2001
ldy  #57            ; 30000 delay
lda  #104     
jsr  delay_ya1
jsr  determine_spr_addr
jsr  print_y        ; prints $00

lda  #$EA
sta  $2003
jsr  sync_ppu_20    ; after return, time = VBL-20
ldy  #140           ; 29560 delay
lda  #41       
jsr  delay_ya3
lda  #$18
sta  $2001          ; writes at VBL+29545
lda  #0
sta  $2001
ldy  #57            ; 30000 delay
lda  #104     
jsr  delay_ya1
jsr  determine_spr_addr
jsr  print_y        ; prints $34

jmp  forever


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 3:02 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
blargg wrote:
Enabling rendering at VBL+29544 (scanline 259, 316 PPU clocks) then disabling causes sprite address to become zero. Enabling rendering one CPU clock later leaves sprite address unaffected.


That kind of makes sense when you think about it. For the PPU to check in-range values for sprites, it needs cycles from pretty much the whole scanline. If you flip the PPU on mid-scanline, it might already be past the time it would need to start in-range checks, so they might not be performed until the next scanline.

Since the end of scanline 259 is near the start of the last rendered scanline -- I guess enabling sprites past that point makes it impossible to do sprite evaluations on the next line


Quote:
Also enabling then disabling before the end of the frame leaves various values in the sprite address (not shown).


I would assume these values reflect the OAM fetches made during sprite evaluations. Kind of like how reading $2004 during rendering exposes what OAM byte the PPU is using -- turning the PPU off during rendering exposes the OAM address the PPU was using.

Ah well -- more assumptions and guessing on my part. Thanks for shedding some light on this mystery blargg. Does this mean we'll be fortunate enough to get a new batch of test ROMs soon? ;D


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 3:56 pm 
Offline

Joined: Sat Mar 19, 2005 11:18 am
Posts: 69
According to the nesdev wiki:

Code:
Cycles 0-63: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF


And...

Code:
On even cycles, data is read from (primary) OAM
On odd cycles, data is written to secondary OAM (unless writes are inhibited, in which case it will read the value in secondary OAM instead)


Perhaps $2003 is used as an index pointer into both primary and secondary OAM by the PPU's internal logic? This would explain why the PPU needs two cycles to copy a single byte from primary to secondary OAM. It would also mean that $2003 would be reset to zero not only at the beginning of the screen, but at the beginning of each active scanline (so that secondary OAM, starting at index $00, could be reset). This could be checked by disabling rendering at carefully timed intervals within a scanline, and then determining whether $2003 points to the location that would be predicted by this hypothesis.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 4:02 pm 
Offline

Joined: Sat Mar 19, 2005 11:18 am
Posts: 69
Alternatively, it's possible that $2003 is only used for reads from the primary OAM. After all, during evaluation, the first byte read from the main OAM is OAM[n][0], which is the first byte of OAM (index $00). Obviously, empirical testing on a real NES will be needed in order to determine what exactly the PPU is doing, but I think it's highly likely given the design philosophy of the PPU that $2003 serves a dual use as both a user register and an internal register during rendering (just as $2004 and the PPU VRAM address do).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 6:04 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Quote:
Does this mean we'll be fortunate enough to get a new batch of test ROMs soon?


I (currently) care little about the details of mid-scanline PPU operation. There are too many details that have little practical use. If it's something that has a significant effect on many games, like clearing $2003 (near) the end of the frame, I'm interested in the general result, but not the details.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 6:51 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
Fair enough.

Clearing $2003 at the end of the frame when the PPU is on will suffice for Akira and the games like it (iirc, some Donkey Kong Country pirate had a similar problem, and some other pirate RPG game.... Phantasy Star I think?)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 12, 2006 4:21 pm 
Offline

Joined: Sat Mar 19, 2005 11:18 am
Posts: 69
So, are we sure that $2003 is cleared at the *end* of the frame, rather than the beginning? Also, do we know if $2003 is cleared *only* at the end of the frame, or is it cleared at the end of each scanline rendered?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 12, 2006 5:36 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
Josh wrote:
So, are we sure that $2003 is cleared at the *end* of the frame, rather than the beginning?


Its value likely fluxuates as the screen is rendering. As blargg has mentioned, turning the PPU off mid-frame leaves $2003 with different values (presumably with what the PPU set it to last)

Quote:
Also, do we know if $2003 is cleared *only* at the end of the frame, or is it cleared at the end of each scanline rendered?


Probably every scanline. Most likely it repeats a similar pattern every scanline as it does sprite fetches (I'd even assume that $2003 reflects the address of the OAM byte the PPU is fetching at any given cycle on the scanline).


Since $2003 cannot be written to or utilized by the CPU during rendering... how it changes mid-frame doesn't really impact emulation at all. Therefore from an emulator standpoint -- the only thing that really matters is what $2003 is at the end of the frame... and when the PPU is turned off mid-frame.

We already know the former is 00... and an educated guess could be made on the latter using the known OAM fetches during the scanlines. But as of yet the latter is unknown.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: MLX and 1 guest


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