background skips when altered...

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

User avatar
Compton
Posts: 20
Joined: Wed Apr 30, 2008 12:48 pm

background skips when altered...

Post by Compton »

I am working a quick demo that alters the background tiles. The catch is when i change some of the tiles, the screen does a visible skip, then resettles where it should be. This doesn't ruin the game in anyway, but i would preferably remove this before a final release.

anyways this is the code i am using the update the location of the screen with a dynamically changing string from RAM...

Code: Select all

        ; Wait a vblank
        lda VBlank
 -      cmp VBlank
        beq -
        
        ;kill ppu
        lda #0
        sta $2000
	sta $2001

        ;Rewrite the word                        
        lda #$22
        sta $2006
        lda #$f2
        sta $2006  
        
        ldy #$00
        
     -  lda (ActiveString), y
        sta $2007
        
        iny
        cpy #$0c  ;word length is 12
        bne -    

        ;This recenters the screen
        lda #$20
        sta $2006
        lda #$00
        sta $2006  

        ;reinitialize ppu
        lda #%10001000
        sta $2000
	lda #%00011110  
	sta $2001
Any advice would be appreciated, as this is the last bug in my otherwise finished demo.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Try also resetting the scroll. Just do

Code: Select all

lda #$00
sta $2005
sta $2005
along with what you have. I don't think you have to write to $2006 if you're still inside natural Vblank.
User avatar
Compton
Posts: 20
Joined: Wed Apr 30, 2008 12:48 pm

Post by Compton »

if i comment out the writes to 2006 to recenter and just clear to scroll, i still get the screen hic-up, but it is less noticable. it is now more of a quick flash, with the location i am writing to at the top of the screen, and then it all centers again.

Thanks for the input. i am still going to see if i can fix it better before releasing it. Is there anything else that i am doing wrong (perhaps expecting a background write to happen smoothly?)
frantik
Posts: 370
Joined: Tue Mar 03, 2009 3:56 pm

Post by frantik »

I'm not sure this will help but maybe you should use a vblank IRQ instead of polling the PPU for vblank?

it seems like you shouldn't see anything if you make all your changes before vblank ends, but i can't say for sure
User avatar
Compton
Posts: 20
Joined: Wed Apr 30, 2008 12:48 pm

Post by Compton »

frantik wrote:I'm not sure this will help but maybe you should use a vblank IRQ instead of polling the PPU for vblank?

it seems like you shouldn't see anything if you make all your changes before vblank ends, but i can't say for sure
Unless i am misunderstanding what you are telling me, i believe i am.

I have the NMI set to trigger on VBlank, where it is incremented.

Other then that, i push the registers onto the stack, then run the next note from the embedded NSF file, then pull the registers back off the stack, and return from interrupt.
frantik
Posts: 370
Joined: Tue Mar 03, 2009 3:56 pm

Post by frantik »

does that code run during the vblank interrupt (like before the RTI command) or do you just increment the VBlank variable, play the note, and return, and then that code executes?

if the graphics code executes after the note is played i think it would cause problems.. but i think you would see more than a "hickup". so i don't really know.. lol
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Post by Roth »

When I was developing Pegs, I had the same issue. I was changing 12 tiles in the background, and when I did so, I got the hiccup you are talking about. I ended up curing this by writing only four tiles at a time, as well as the using the same code that Celius posted, I believe (check the source, because I honestly do not remember at this point). I'm pretty sure I just polled $2002 each time before writing, which as I understand from other posts isn't the best way, but it worked for me, and I've never experienced any lag on that game when played on the system.

It kind of makes me wonder if there is a time when polling $2002 on the NES is acceptable, but has to be done at a certain point in the cycles. I don't know, I'm just speculating : P
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Roth wrote:It kind of makes me wonder if there is a time when polling $2002 on the NES is acceptable
Soon after power-on, in order to make sure the PPU reset finished all the way. The typical sequence is poll $2002, clear CPU RAM, poll $2002, set palette, clear nametables. There's about a 1 out of 21 chance that you'll get lag on any frame; this chance is acceptable in something like power-on. But after that, use NMI.
User avatar
Compton
Posts: 20
Joined: Wed Apr 30, 2008 12:48 pm

Post by Compton »

Well this code is meant to run under certain conditions of an 'A' press.

I don't want to rewrite the background every time the NMI is triggered (or at least the 12 tiles.) So unless i create a state system to handle different types of background writes, then embed that code into the NMI to handle those writes, that wont work.

One of my goals in this demo was to create a simple procedural example of coding on the NES, but this adds needless complication for an inexperienced observer.

If the aforementioned state system is my only option, i will take it, but i would prefer handling it in inline code to make it easier on the newbies that happen to read the source, or use it as a reference.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

So Vblank is a variable incremented in the NMI? Exactly what is happening when the NMI is fired?

Oh, and really make sure in your NMI routine you save A, X, and Y. If the A register is destroyed, the desired value won't be loaded into A upon returning.

Here's my suggestion: put "STA $5555" at the very end of the posted code. Then open the ROM in FCEUXD. Go to Tools... Debug... Then under the "break points" box click "add". Then in the first text box next to "address" write $5555 and under it, click "write", then "OK". Then press 'A'.

It will break after that code is done. You can see what scanline it ends at and other information.

And writing less probably isn't the answer. I was able to fit 182 PPU writes into 1 Vblank, so you just have to keep track of how many cycles everything is taking. Make sure it doesn't spill out of Vblank. That's probably what's causing the problem here, actually.
User avatar
Compton
Posts: 20
Joined: Wed Apr 30, 2008 12:48 pm

Post by Compton »

This is my NMI interrupt code...

Code: Select all

NMI:

  ;Alter the VBlank flag
  inc VBlank	
  

  ;Push registers onto stack
  pha
  txa
  pha
  tya
  pha
  	
  ;Play the next Music note
  jsr PLAY_ADDR 

  ;Pull registers from stack
  pla
  tay
  pla
  tax
  pla
	
rti	;Return from interrupt

I try to keep it simple as possible and handle most timing by tracking the VBlank flag.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

You're supposed to handle music after you handle the graphics. This is because the PSG allows writes at any time, not just during blanking.

If you don't use a register in your NMI handler, you don't need to spend cycles saving and loading it. My NES programs' NMI code typically looks like this:

Code: Select all

nmi:
  inc retraces
  rti
And then your main loop will look like this:

Code: Select all

forever:
  jsr read_pads  ; read each controller twice and keep readings that agree
  jsr game_logic  ; apply all game rules
  jsr prepare_ppu  ; prepare data to be copied to OAM and VRAM
  lda retraces
:
  cmp retraces  ; wait for NMI handler to signal the start of vblank
  beq :-
  jsr update_ppu  ; partly-unrolled copies from CPU RAM to tiles, nametables, palette
  jsr PLAY_ADDR
  jmp forever
frantik
Posts: 370
Joined: Tue Mar 03, 2009 3:56 pm

Post by frantik »

is there a reason it's better to increment a variable inside of vblanks iterrupt routine and then handle the variable change, vs just putting the handling code between the interrupt vector and the RTI?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

frantik wrote:is there a reason it's better to increment a variable inside of vblanks iterrupt routine and then handle the variable change, vs just putting the handling code between the interrupt vector and the RTI?
No, except that the pattern of an ISR that just sets a flag might be more familiar to developers on platforms where you don't get to write your own ISRs, such as any multitasking OS. You could put the entire game in the NMI; Super Mario Bros. does just this. Just make sure you do the PPU updates as soon as possible after the start of vblank, which means before you run the sound engine.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Polling the VBL count is simpler to code for, because you don't have to deal with re-entrancy and concurrency issues. If the code is executed from NMI, you need a flag to tell it when it can run, and where it's called from the mainline code is less-clear. Unless you're doing split-screen effects, you don't need code guaranteed to run every NMI, so the polling approach is better.
Post Reply