Scroll glitch while turning of PPU right after NMI

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
yaros
Posts: 145
Joined: Tue Aug 28, 2018 8:54 am
Location: Edmonton, Canada

Scroll glitch while turning of PPU right after NMI

Post by yaros » Wed Feb 13, 2019 9:06 am

Even though I make sure I always turn off PPU after NMI, I still have scroll showing garbage from the other nametable for one frame (in Mesen).

I wait for NMI using standard approach with the flag

Code: Select all

.proc ppu_WaitForNmiDone
@forever:
    lda ppu_nmi_done ; Execute main loop once per frame
    beq @forever
    lda #0
    sta ppu_nmi_done ; Reset the flag
    rts
.endproc
I set this flag at the end of the NMI (and reset scroll at the end of NMI as that helped me with some glitches).

Code: Select all

nmi:
    pushseg
    ; Write to OAM DMA
    lda ppu_needOam
    beq @oamEnd
        mova ppu_needOam, #0 ; reset OAM flag
        lda #<ppu_oam
        sta PPU_SPR_ADDR
        lda #>ppu_oam
        sta APU_SPR_DMA
    @oamEnd:

    ; Fix scroll
    mova PPU_SCROLL, ppu_scrollx
    mova PPU_SCROLL, ppu_scrolly

    @end:
    lda #1
    sta ppu_nmi_done
    popseg
    rti
In "ppu_Off" code I reset the flag in case we are past v-blank and wait for NMI again.

Code: Select all

.proc ppu_Off
    lda #0           ; reset nmi flag
    sta ppu_nmi_done
    jsr ppu_WaitForNmiDone
    lda #0
    sta ppu_needOam
    lda #0
    sta PPU_MASK
    rts
.endproc
What am I doing wrong? Should I do something before/after putting #0 into the PPU_MASK?

Thank you

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scroll glitch while turning of PPU right after NMI

Post by tokumaru » Wed Feb 13, 2019 9:37 am

A full scroll reset needs a write to $2000, in addition to the 2 writes to $2005. Seeing as the missing $2000 write is supposed to select the name table where the scroll starts at, and you're seeing "the other name table", this might be it.

I don't understand the purpose of "ppu_Off" though.

yaros
Posts: 145
Joined: Tue Aug 28, 2018 8:54 am
Location: Edmonton, Canada

Re: Scroll glitch while turning of PPU right after NMI

Post by yaros » Wed Feb 13, 2019 10:02 am

tokumaru wrote:A full scroll reset needs a write to $2000, in addition to the 2 writes to $2005. Seeing as the missing $2000 write is supposed to select the name table where the scroll starts at, and you're seeing "the other name table", this might be it.
It didn't seem to help. Is this the correct order?

Code: Select all

.proc ppu_ResetScroll
    mova PPU_CTRL, ppu_ctrl ; just saved values, I never change coarse scrooll
    mova PPU_SCROLL, ppu_scrollx
    mova PPU_SCROLL, ppu_scrolly
    rts
.endproc
.proc ppu_On
    lda #0           ; reset nmi flag
    sta ppu_nmi_done
    jsr ppu_WaitForNmiDone
    mova PPU_CTRL, ppu_ctrl
    mova PPU_MASK, ppu_mask
    jsr ppu_ResetScroll
    rts
.endproc
tokumaru wrote: I don't understand the purpose of "ppu_Off" though.
To turn of PPU, clear the whole nametable, turn it back on.

Code: Select all

jsr ppu_Off               ; turn off PPU
lda #>PPU_ADDR_NAMETABLE1 ; nametable
ldx #$20                  ; tile
ldy #0                    ; attribute
jsr ppu_FillNameTable     ; clear nametabnle
jsr ppu_On                ; turn on PPU

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scroll glitch while turning of PPU right after NMI

Post by tokumaru » Wed Feb 13, 2019 10:14 am

When are you getting the wrong scroll exactly? Is it just for a frame when turning rendering on?

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scroll glitch while turning of PPU right after NMI

Post by tokumaru » Wed Feb 13, 2019 10:22 am

Are pushseg and popseg backing up and restoring the CPU registers in the NMI handler? Those names are kinda misleading, since ca65 has directives with those names and they do something else. Maybe pushreg and popreg instead?

Anyway, just wanted to be sure that the registers are being preserved in the NMI handler, since your main thread relies on the accumulator being preserved in order to detect NMIs (and in case of lag frames you need X and Y to be backed up too).

lidnariq
Posts: 8703
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Scroll glitch while turning of PPU right after NMI

Post by lidnariq » Wed Feb 13, 2019 10:22 am

What scroll value does Mesen show for the garbage frame?

yaros
Posts: 145
Joined: Tue Aug 28, 2018 8:54 am
Location: Edmonton, Canada

Re: Scroll glitch while turning of PPU right after NMI

Post by yaros » Wed Feb 13, 2019 11:20 am

tokumaru wrote:When are you getting the wrong scroll exactly? Is it just for a frame when turning rendering on?
Right after NMI is done, even though NMI always reset the scroll before exit
tokumaru wrote:Are pushseg and popseg backing up and restoring the CPU registers in the NMI handler? Those names are kinda misleading, since ca65 has directives with those names and they do something else. Maybe pushreg and popreg instead?
Yeah, these names are from the couple months ago when I started to learn NES and build the library of subroutines and macroses.
lidnariq wrote:What scroll value does Mesen show for the garbage frame?
Funny enough, unless I'm stupid and read wrong value it is 0. Problem is, in debugger Mesen does not turn screen of even though $2001 is 0, so I can't say for sure.
Attachments
bug.png

lidnariq
Posts: 8703
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Scroll glitch while turning of PPU right after NMI

Post by lidnariq » Wed Feb 13, 2019 11:32 am

yaros wrote:Funny enough, unless I'm stupid and read wrong value it is 0.
So the screen shot shows right after the bad frame. The PPU viewer implies your scroll is somehow $237B during the bad frame (upper left corner of grey box is at tile (27,28) fine Y scroll 2)—which sounds like something somewhere is trying to write to the PPU before it should.

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scroll glitch while turning of PPU right after NMI

Post by tokumaru » Wed Feb 13, 2019 3:18 pm

Yeah, I'm not seeing anything obvious here that could be causing the problem, so there must be something else influencing this logic.

One thing that I personally don't like is that the NMI flag is being manipulated in various places, because that might result in conflicts. A better approach would be to have the NMI simply INC a variable, so that you can wait for the NMI just by waiting for that variable to change:

Code: Select all

NMI:
  (...)
  inc FrameCounter
  rti

WaitForNMI:
  lda FrameCounter
@loop:
  cmp FrameCounter
  beq @loop
  rts
Not only is this shorter and faster, but it's also safer, because it's not possible for different routines to step on each other's toes and put the flag in inconsistent states. I'm not saying this will solve your current problem, but it could about headaches in the long run run.

Another minor correction I have is that the $2003 (PPU_SPR_ADDR) write is NOT meant to set the low byte of the address of your OAM mirror, it's actually meant to set the TARGET position in OAM where the transfer will begin. The code works because this is usually 0 anyway, but the way the code is written suggests the wrong concept. This is a misconception that's still being spread by some tutorials.

gravelstudios
Posts: 70
Joined: Mon Mar 13, 2017 5:21 pm
Contact:

Re: Scroll glitch while turning of PPU right after NMI

Post by gravelstudios » Thu Feb 14, 2019 6:37 pm

Not to change the subject, but...

Code: Select all

NMI:
  (...)
  inc FrameCounter
  rti

WaitForNMI:
  lda FrameCounter
@loop:
  cmp FrameCounter
  beq @loop
  rts
Tokumaru, when I saw this, I immediately put it into my current project. I was using a separate boolean to keep track of when my NMI routine was finished. It didn't occur to me to use the frame counter to do it. Thanks. You saved me a few bytes and cycles.

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scroll glitch while turning of PPU right after NMI

Post by tokumaru » Thu Feb 14, 2019 10:45 pm

Cool. I think it was tepples who first pitched this idea around here.

yaros
Posts: 145
Joined: Tue Aug 28, 2018 8:54 am
Location: Edmonton, Canada

Re: Scroll glitch while turning of PPU right after NMI

Post by yaros » Fri Feb 15, 2019 9:51 am

tokumaru wrote:Yeah, I'm not seeing anything obvious here that could be causing the problem, so there must be something else influencing this logic.

One thing that I personally don't like is that the NMI flag is being manipulated in various places, because that might result in conflicts. A better approach would be to have the NMI simply INC a variable, so that you can wait for the NMI just by waiting for that variable to change:

Code: Select all

NMI:
  (...)
  inc FrameCounter
  rti

WaitForNMI:
  lda FrameCounter
@loop:
  cmp FrameCounter
  beq @loop
  rts
Not only is this shorter and faster, but it's also safer, because it's not possible for different routines to step on each other's toes and put the flag in inconsistent states. I'm not saying this will solve your current problem, but it could about headaches in the long run run.

Another minor correction I have is that the $2003 (PPU_SPR_ADDR) write is NOT meant to set the low byte of the address of your OAM mirror, it's actually meant to set the TARGET position in OAM where the transfer will begin. The code works because this is usually 0 anyway, but the way the code is written suggests the wrong concept. This is a misconception that's still being spread by some tutorials.
Thank you, tokumaru. I haven't had a chance to test it yet, but I appreciate suggestions. One question though, I do not see how you reset FrameCounter in WaitForNmi. Is it missing "dec"?

tepples
Posts: 21720
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Scroll glitch while turning of PPU right after NMI

Post by tepples » Fri Feb 15, 2019 10:02 am

You don't need to reset it. If FrameCounter contains $38 before you wait for vblank, then $38 gets loaded into A. The loop continues until FrameCounter becomes no longer $38.

yaros
Posts: 145
Joined: Tue Aug 28, 2018 8:54 am
Location: Edmonton, Canada

Re: Scroll glitch while turning of PPU right after NMI

Post by yaros » Fri Feb 15, 2019 10:37 am

tepples wrote:You don't need to reset it. If FrameCounter contains $38 before you wait for vblank, then $38 gets loaded into A. The loop continues until FrameCounter becomes no longer $38.
Oops... I should have paid more attention. Thank you tepples! This is very clever way to do so.
lidnariq wrote:So the screen shot shows right after the bad frame. The PPU viewer implies your scroll is somehow $237B during the bad frame (upper left corner of grey box is at tile (27,28) fine Y scroll 2)—which sounds like something somewhere is trying to write to the PPU before it should.
lidnariq and tokumaru, you were both right. But it was something that SHOULD have written to ppu but I forgot to reset scroll... I do not buffer my PPU writes because I only output one of none bytes per frame. But when screen is full and I want to clear it, I forgot to reset scroll after write.

Code: Select all

* nmi finished
* set address
* write to ppu
- missing reset scroll
* turn ppu off (while waiting to make sure NMI finishes, which resulted in one frame being with broken scroll value)

Post Reply