CHR-RAM Image Corruption Issue

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Lucradan
Posts: 101
Joined: Wed Sep 21, 2016 12:08 pm

CHR-RAM Image Corruption Issue

Post by Lucradan »

I'm trying to use CHR-RAM but am having a problem when I try to copy the pattern table data from PRG ROM.

Here is my NMI Code

Code: Select all

LBL.NMI:

  PHA
  TXA
  PHA
  TYA
  PHA

LDA FLAG.NMI.Update.Background	
BNE LBL.NMI.LoadBackground
  JMP LBL.NMI.LoadTiles

LBL.NMI.LoadBackground:
  LDA FALSE
  STA FLAG.NMI.Update.Background	

  LDA #$00
  STA $2001

  LDA $2002
  LDA #$20
  STA $2006
  LDA #$00
  STA $2006

  LDX #$04
  LDY #$00
LBL.LoadBackground.Nametable.Loop:
    LDA (PTR.Background.Nametable), y
    STA $2007
    INY
    BNE LBL.LoadBackground.Nametable.Loop
      INC PTR.Background.Nametable + 1;
      DEX
      BNE LBL.LoadBackground.Nametable.Loop

LBL.NMI.LoadTiles:
  LDA FLAG.NMI.Update.Bank
  BNE LBL.NMI.LoadTiles.Continue
    JMP LBL.NMI.Reset

LBL.NMI.LoadTiles.Continue:	
  LDA FALSE
  STA FLAG.NMI.Update.Bank
  
  LDA $2002
  LDA #$00
  STA $2006
  STA $2006

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

PLA
TAY
PLA
TAX
PLA
RTI

LBL.NMI.Reset:

  LDA #%10001000
  STA $2000
  LDA #%00011110
  STA $2001
  LDA #$00
  STA $2005
  STA $2005

  INC VAR.Frame
  
  PLA
  TAY
  PLA
  TAX
  PLA
  RTI
The Level Initiation Loop is given below

Code: Select all

LBL.State.Game.Initialize:
  JSR LBL.Wait.Frame
  JSR LBL.Jumper.Scene.Initialize
  LDA #State.Game.Update
  STA VAR.State.Game
  RTS

LBL.Wait.Frame:
  LDA VAR.Frame
LBL.Wait.Frame.Loop:
  CMP VAR.Frame
  BEQ LBL.Wait.Frame.Loop
RTS

It works great until I increase the number of pages to copy from 3 to 4 or more ("LDX #$03 to LDX #$04"). Then the PPU becomes corrupted.

I'm missing something, but can't tell if it's a coding error or fundamental misunderstanding about the PPU Enable/Disable and NMI timing.

Thank you for any help!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: CHR-RAM Image Corruption Issue

Post by tokumaru »

Normally you wouldn't be doing this kind of heavy VRAM updating in the NMI, which is more for incremental frame-to-frame updates, so my guess is that you have multiple NMIs firing before the previous instances have time to finish (i.e. they're taking longer than a frame to finish), and they end up using "corrupted" flags, pointers and the like.
User avatar
Lucradan
Posts: 101
Joined: Wed Sep 21, 2016 12:08 pm

Re: CHR-RAM Image Corruption Issue

Post by Lucradan »

I thought that too so I tried adding a disable NMI command (STA $2000) at the beginning of the NMI to see if that would fix the problem and it didn't. It made it worse. I also tried using the debugger in FCEUX to see if a second NMI is being triggered before I complete the loop (using breakpoints) and it wasn't. The more I look at the problem, the more I wonder if it's a flaw in the engine. I'll look at how I might effeciently pull the scene initialization code out of the NMI.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: CHR-RAM Image Corruption Issue

Post by unregistered »

Just want to pass on a smaller LBL.Wait.Frame that someone from this forum recommended me use.

Code: Select all

- lda $2002
bpl -
I don't know if this will solve your problem, but you need to wait two vblanks during startup. And I would also recommend not using two jsrs to LBL.Wait.Frame; instead just place those two lines of code twice cause the jsrs are slow and you lose cycles for each use of them. JSRs are good; you can input sections of code using only 3 bytes; that helps with padding correctly; and if you jsr a function twice or more that is a good use; macro functions only JSRed once, unless you need to use only three bytes for padding purposes. :)

edit: Want to clear this up. JMP and RTS, together, take 12 cycles to run, so you would save 24 cycles if you followed my advise and save 2 bytes.

Code: Select all

- lda $2002
bpl -

- lda $2002
bpl -
takes 10 bytes

Code: Select all

jsr LBL.Wait.Frame
jsr LBL.Wait.Frame

LBL.Wait.Frame:
- lda $2002
bpl -
rts 
takes 12 bytes. Hope this will be helpful to someone. Glad your code is working now! tokumaru is so very smart and helpful. :D
Last edited by unregistered on Fri Aug 04, 2017 1:21 pm, edited 1 time in total.
User avatar
Lucradan
Posts: 101
Joined: Wed Sep 21, 2016 12:08 pm

Re: CHR-RAM Image Corruption Issue

Post by Lucradan »

I have this when I'm simply waiting for an NMI call, but the Wait.Frame specifically watches the frame count variable for a change in value. If I'm doing partial frame updates in each NMI, I can use my code to wait over several NMIs before continuing.
User avatar
Lucradan
Posts: 101
Joined: Wed Sep 21, 2016 12:08 pm

Re: CHR-RAM Image Corruption Issue

Post by Lucradan »

tokumaru wrote:Normally you wouldn't be doing this kind of heavy VRAM updating in the NMI, which is more for incremental frame-to-frame updates, so my guess is that you have multiple NMIs firing before the previous instances have time to finish (i.e. they're taking longer than a frame to finish), and they end up using "corrupted" flags, pointers and the like.
I removed the Screen Initialization Code from the NMI logic and that fixed all my problems!
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: CHR-RAM Image Corruption Issue

Post by unregistered »

Lucradan wrote:I have this when I'm simply waiting for an NMI call, but the Wait.Frame specifically watches the frame count variable for a change in value. If I'm doing partial frame updates in each NMI, I can use my code to wait over several NMIs before continuing.
That's pretty cool, I kind of see that now. :) Wow, my first comment was totally off; I'm sorry, waiting for two frames is only needed in the reset code... not in the NMI code. I made a mistake. :(

Everywhere you have:

Code: Select all

bne
jmp
you can save a byte with

Code: Select all

bne
beq
cause the BEQ will work just like a JMP if it follows a BNE. Just make sure the beq branches to the same page. :)

edit
Post Reply