It is currently Sat Oct 20, 2018 1:11 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 1:44 pm 
Offline
User avatar

Joined: Wed Sep 21, 2016 12:08 pm
Posts: 83
I wrote some code to load pattern tiles onto the PPU, but I am having a strange bug I cannot seem to figure out. The code is below. I am using FCEUX 2.2.3, New PPU enabled. The pattern table I have included has NINE pages (or 9 x 16 tiles = 2304 bytes). When I set NUMPAGES to 9 all I get is a gray screen. When I set it to 10 I have an extra page of garbage tiles in the PPU, but the ROM works fine. If I set the NUMPAGES to 10 and add a DEX command immediately after the LDX command it also works and I don't have the extra garbage tiles in the PPU. If I set NUMPAGES to 9 and add a NOP command right after the LDX it also works. Does anyone have a clue what might be causing this? I've never seen any timing bug like this before.

Code:
  NUMPAGES = 10

  LDA $2002
  LDA #$00
  STA $2006
  STA $2006
  LDX #NUMPAGES
  LDY #$00
LBL.OriginStory.LoadTiles.Background.Loop:
    LDA (PTR.Tiles),y
    STA $2007
    INY
    BNE LBL.OriginStory.LoadTiles.Background.Loop
     INC PTR.Tiles+1;
     DEX
     BNE LBL.OriginStory.LoadTiles.Background.Loop


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 1:48 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20676
Location: NE Indiana, USA (NTSC)
What's in your NMI handler? What address is LBL.OriginStory.LoadTiles.Background.Loop getting assembled at? You can use your assembler's map file or place a breakpoint on $2006 writes to answer the latter.

I ask because I'm guessing some combination of page crossing and NMI clobbering registers.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 1:59 pm 
Offline
User avatar

Joined: Wed Sep 21, 2016 12:08 pm
Posts: 83
Here is the FCEUX debugger code. It looks like 00:82D2

Code:

 00:82C2:AD 02 20  LDA PPU_STATUS = #$40
 00:82C5:A9 00       LDA #$00
 00:82C7:8D 06 20  STA PPU_ADDRESS = #$02
 00:82CA:8D 06 20  STA PPU_ADDRESS = #$02
 00:82CD:A2 09       LDX #$09
 00:82CF:EA            NOP
 00:82D0:A0 00       LDY #$00
 00:82D2:B1 10       LDA ($10),Y @ $B740 = #$00
 00:82D4:8D 07 20  STA PPU_DATA = #$00
 00:82D7:C8           INY
 00:82D8:D0 F8      BNE $82D2
 00:82DA:E6 11      INC $0011 = #$B7
 00:82DC:CA          DEX
 00:82DD:D0 F3     BNE $82D2


My NMI handler is here

Code:
;--------------------------------------------------------------------
;CODE:  NMI
;--------------------------------------------------------------------
LBL.NMI:

  PHA
  TXA
  PHA
  TYA
  PHA
 
  LDA FLAG.NMI.Wait
  BEQ LBL.NMI.LoadPalette.Sprites
    JMP LBL.NMI.Exit 

LBL.NMI.LoadPalette.Sprites:
  LDA FLAG.NMI.Update.Sprites.Palette
  BEQ LBL.NMI.LoadPalette.Background
    LDA $2002
    LDA #$3F
    STA $2006
    LDA #$10
    STA $2006 
    LDX #$00
    LBL.NMI.LoadPalettes.Sprites.Loop:
      LDA BUF.Palette.Sprites, X
      STA $2007
      INX
      CPX #$10
      BNE LBL.NMI.LoadPalettes.Sprites.Loop
   
   
LBL.NMI.LoadPalette.Background:
  LDA FLAG.NMI.Update.Background.Palette
  BEQ LBL.NMI.UpdateSprites
    LDA $2002
    LDA #$3F
    STA $2006
    LDA #$00
    STA $2006   
    LDX #$00
    LBL.NMI.LoadPalettes.Background.Loop:
      LDA BUF.Palette.Background, X
      STA $2007
      INX
      CPX #$10
      BNE LBL.NMI.LoadPalettes.Background.Loop
 


LBL.NMI.UpdateSprites:
  LDA FLAG.NMI.Update.Sprites
  BEQ LBL.NMI.Exit
    LDA #$00
    STA $2003
    LDA #>BUF.Sprites
    STA $4014
   LDA FALSE
    STA FLAG.NMI.Update.Sprites   

LBL.NMI.Exit:
  LDA #%10001000
  STA $2000
  LDA #$00
  STA $2005
  STA $2005
  INC VAR.Frame
  PLA
  TAY
  PLA
  TAX
  PLA
  RTI


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 4:33 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2305
Location: DIGDUG
Assuming you've correctly set FLAG.NMI.Wait to avoid the reads from 2002 and writes to 2006/2007...

I believe the 2 writes to $2005 at the end of NMI might be the problem, but I can't remember exactly how they affect 2006/2007 writes.

Personally, I turn off NMIs during large block writes to the PPU.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 4:42 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1437
dougeff wrote:
Assuming you've correctly set FLAG.NMI.Wait to avoid the reads from 2002 and writes to 2006/2007...

I believe the 2 writes to $2005 at the end of NMI might be the problem, but I can't remember exactly how they affect 2006/2007 writes.


Writing $2000/$2005/$2005 at the end of NMI is the correct way of resetting the VRAM address for rendering, and it overrides whatever you wrote to $2006 previously.

However, the most important part is to ensure that it's before the end of VBLANK, which means you need to make sure your VRAM writes aren't taking too long (and that you do it before other non-essential stuff like reading controller input or updating your sound engine).

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 5:38 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2305
Location: DIGDUG
but it's not his NMI code doing the buggy writes. it's his main code, and the NMI code is interrupting it, I think.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 5:58 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10901
Location: Rio de Janeiro - Brazil
If the code that loads patterns is interrupted by the NMI, and the NMI uses any of $2000, $2005, $2006 or $2007, that will certainly interfere with the VRAM address and mess up the update. If you're keeping NMIs on while the main thread performs PPU updates (which is a good thing, because you can continue playing sounds during screen transitions, for example), be sure to implement a way to skip all PPU operations if rendering is disabled. I normally check the buffered copy of PPUMASK to know whether it's safe to use the PPU in the NMI handler or not.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 8:27 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1437
Ah, I misunderstood what was going on - that's what I get for not fully reading the entire thread.

One solution to this problem is to just ensure that an NMI will never occur during VRAM writes - either disable NMI during any VRAM writes (which is probably a good idea anyways), or schedule them to occur during your NMI routine.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 8:48 pm 
Offline
User avatar

Joined: Wed Sep 21, 2016 12:08 pm
Posts: 83
Most likely that is the problem.

The initialization code for that screen begins with

Code:
  ; Disable Rendering
  LDX #$00
  STX $2001    ; disable rendering
 
  ; Set NMI to Wait
  LDA TRUE
  STA FLAG.NMI.Wait


And ends with

Code:
  ; Set NMI FLAGS
  LDA FALSE
  STA FLAG.NMI.Wait 
  LDA TRUE
  STA FLAG.NMI.Update.Sprites.Palette
  STA FLAG.NMI.Update.Background.Palette
  STA FLAG.NMI.Update.Sprites   

  ; Wait for Next NMI
   - BIT $2002
    BPL -
   
  ; Set NMI FLAGS
  LDA FALSE
  STA FLAG.NMI.Wait
  STA FLAG.NMI.Update.Sprites.Palette
  STA FLAG.NMI.Update.Background.Palette
 
  ; Re-Enable Rendering
  LDA #%00011110
  STA $2001


It seems I need to add another NMI FLAG that can bypass the $2005 writes. Something like

Code:
LBL.NMI.Exit:
  LDA FLAG.NMI.BlockWrite
  BNE LBL.NMI.BlockWriteBypass
    LDA #%10001000
    STA $2000
    LDA #$00
    STA $2005
    STA $2005
LBL.NMI.BlockWriteBypass:
  INC VAR.Frame
  PLA
  TAY
  PLA
  TAX
  PLA
  RTI


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 8:59 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10901
Location: Rio de Janeiro - Brazil
Quietust wrote:
either disable NMI during any VRAM writes (which is probably a good idea anyways)

Unless you want music to keep playing during screen transitions... It can be weird in screen-by-screen or room-by-room games to have the music interrupted or distorted every time new screens/rooms are loaded.

I usually leave NMIs on all the time, and use flags and other variables to make sure the NMI handler doesn't screw up anything the main thread is doing.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Thu Jan 04, 2018 10:21 pm 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3569
Location: Indianapolis
Shouldn't you have LDA #TRUE instead of LDA TRUE? I guess you might have TRUE defined with the # built-in, but it makes it like you're using a variable.. seems confusing. Definitely would recommend avoiding that when using constants, better to type one more character and have the code look more clear.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Fri Jan 05, 2018 8:05 am 
Offline
User avatar

Joined: Wed Sep 21, 2016 12:08 pm
Posts: 83
Memblers wrote:
Shouldn't you have LDA #TRUE instead of LDA TRUE?


TRUE/FALSE are values, not variables so I decided not to use the # to deferentiate.

My normal convention for variables IS to use the #.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Fri Jan 05, 2018 9:09 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10901
Location: Rio de Janeiro - Brazil
But... it's the other way around: # is used for immediate values, and no # is used for variables (i.e. aliases for memory positions).


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Fri Jan 05, 2018 9:11 am 
Offline

Joined: Sun Mar 27, 2011 10:49 am
Posts: 266
Location: Seattle
...and to be totally clear, it's not a convention or choice for the individual programmer - the assembler will assemble the instruction into different opcodes based on whether or not there's a '#' to indicate the immediate addressing mode.


Top
 Profile  
 
 Post subject: Re: Strange Timing Bug
PostPosted: Mon Jan 08, 2018 10:02 am 
Offline
User avatar

Joined: Wed Sep 21, 2016 12:08 pm
Posts: 83
Here is my constant declaration header and how I handle the True/False. Probably not the best way, but it helps me to differentiate between CPU variables (those defined using .dsb/dsw that have a memory location), compiler variables (such as PRGCOUNT), and compiler enumerations (TRUE/FALSE).

Code:

PRGCOUNT = 2 ; 16kb = 1, 32kb = 2, etc.
CHRCOUNT = 0
MIRRORING = %0000 ; Horizontal =  %0000, Vertical =    %0001, Four Screen = %1000
FALSE             EQU #$00
TRUE            EQU #$01



Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 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