It is currently Thu Sep 21, 2017 8:57 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sat Aug 12, 2017 8:02 pm 
Offline

Joined: Fri Oct 28, 2016 12:37 pm
Posts: 15
Hi all

I'm able to initialize and render my first nametable just fine (start screen), but am having trouble trying to load a second nametable upon starting the game (play screen).

Here is what I'm doing:

1. During NMI I check for the start button press during my initial game state. If this happens I set a change state flag.
2. During my 'Forever' loop, outside of NMI, I check if the change flag is set, and if so, I update my game state then disable NMI:

Code:
LDA #%00000000
STA $2000


3. I call a subroutine to repopulate my nametable. The code to populate is the same as my initial population code of the nametable, with the only difference being my pointer points to a new nametable dataset. (planning on making this subroutine reusable later by making what the pointer points to dynamic, for testing I'm just hardcoding it).

Code:
LoadPlayNametable:
    LDA $2002             ; read PPU status to reset the high/low latch
    LDA #$20
    STA $2006             ; write the high byte of $2000 address
    LDA #$00
    STA $2006             ; write the low byte of $2000 address

    LDA #LOW(PlayNametable)
    STA pointerLow
    LDA #HIGH(PlayNametable)
    STA pointerHigh

    LDX #$00
    LDY #$00

LoadPlayNametableLoop:
        LDA [pointerLow], y
        STA $2007
        INY
        CPY #$00
        BNE LoadPlayNametableLoop
        INC pointerHigh
        INX
        CPX #$04
        BNE LoadPlayNametableLoop

    RTS


4. Upon return of this subroutine I re-enable NMI and sprites (not using sprites at the moment)

Code:
LDA #%10010000
STA $2000


I can tell the logic is triggering, but my screen looks like the starting nametable just got mixed around. I see one tile from nametable 2, and I still see tiles from nametable 1.

I've been doing some reading on here and have learned something like this should not happen during NMI, and NMI should be off, so curious why this fails to work.


Top
 Profile  
 
PostPosted: Sat Aug 12, 2017 8:47 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10010
Location: Rio de Janeiro - Brazil
Apparently you're not disabling rendering before writing the new data to the PPU. You absolutely can't access VRAM while the PPU is rendering, if you try you'll get visual glitches and corrupted VRAM.

This is why we can only do visual updates (sprite DMA, pallette updates, small NT changes, etc.) during vblank, a time during which the PPU is not rendering images. For big updates, such as a whole NT, the vblank period isn't enough, so you have to completely disable background and sprite rendering (using register $2001) in order to have free access to VRAM. When you're done transferring the data, you can turn rendering back on.


Top
 Profile  
 
PostPosted: Sat Aug 12, 2017 9:06 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6162
Location: Seattle
tokumaru wrote:
so you have to completely disable background and sprite rendering (using register $2001) in order to have free access to VRAM. When you're done transferring the data, you can turn rendering back on.
Or, schedule the updates over multiple vblanks. You may find yourself wanting a PPU update system anyway.


Top
 Profile  
 
PostPosted: Sat Aug 12, 2017 11:03 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10010
Location: Rio de Janeiro - Brazil
If you ever plan on implementing scrolling, background animations and the like, then yeah, it makes sense to start thinking of a flexible VRAM update system that makes use of the vblank time. If you prefer to start simple, turning rendering off between screens is conceptually simpler, and even people who have more advanced VRAM management may still prefer to turn rendering off during screen transitions and have unlimited VRAM access in order to simplify and speed up larger updates, that may need to replace not only name tables, but also pattern tables.


Top
 Profile  
 
PostPosted: Sat Aug 12, 2017 11:49 pm 
Offline

Joined: Fri Oct 28, 2016 12:37 pm
Posts: 15
That was the missing piece! Turning off the bits I had in $2001, so close. Screen switch works perfectly now, thanks guys!


Top
 Profile  
 
PostPosted: Wed Sep 06, 2017 11:02 pm 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 235
Is the write to $ 2001 (disable / enable screen) must be done only during NMI (VBLANK)? Because I guess I'm wrongly turning off / on the screen when I change the nametable. I would like to make sure on this. For example:

Code:
LoadLevel:

   JSR DisablePPU              ;outside NMI/VBLANK
   JSR LoadSomeData
   JSR LoadSprites
   JSR LoadPalettes
   JSR LoadNametable
   JSR EnablePPU            ;outside NMI/VBLANK

   RTS

;------------------------------------

EnablePPU:              ;outside NMI/VBLANK
   LDA #%10010000
   STA $2000
   LDA #%00011110
   STA $2001
   RTS

;------------------------------------

DisablePPU:              ;outside NMI/VBLANK
   LDA #%00000000
   STA $2000
   LDA #%00000000
   STA $2001
   RTS


Top
 Profile  
 
PostPosted: Wed Sep 06, 2017 11:31 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6162
Location: Seattle
Best to only toggle it during NMI, yes.

Turning off rendering at the wrong time during rendering can cause sprites to be wrong during the next frame in which rendering is enabled again.

Turning on rendering during the would-be-active portion will most likely cause the contents of the screen to be wrong for the remainder of that frame.


Top
 Profile  
 
PostPosted: Thu Sep 07, 2017 12:31 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 235
So I always wrongly did it.

I have a problem modifying this code so that its meaning stays the same, but the "DisablePPU" and "EnablePPU" codes were executed during VBLANK. So the LoadLevel code stays out of the NMI, but the Disable / EnablePPU code is executed correctly.




Code:
NMI:

 lda <PPU0
 sta PPUCTRL
 lda <PPU1
 sta PPUMASK

RTI

;------------------------------------

EnablePPU:
   LDA #%10010000
   STA  <PPU0
   LDA #%00011110
   STA  <PPU1
   RTS

;------------------------------------

DisablePPU:
   LDA #%00000000
   STA  <PPU0
   LDA #%00000000
   STA  <PPU1
   RTS


Will it be ok?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 7 hours


Who is online

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