My sprites are flickering on real NES, not in any of 4 emus.

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
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

My sprites are flickering on real NES, not in any of 4 emus.

Post by GradualGames »

I had a nasty surprise this evening when I tested some of my experiments on a real NES. I thought I had tested this particular experiment on a real NES before, but apparently not. I'm getting nasty sprite flicker. It sucks cause this doesn't happen on any of the 4 emulators I've been testing with.

The only thing I can think is maybe I've written some highly inefficient, cycle-heavy code and it is going past the length of one vblank (but shouldn't an accurate emulator catch this?). In fact, I did add one (harmless) instruction in my code and the flicker got worse...that would lend credence to that possibility would it not?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

There are two things I can see that would cause differences between Nintendulator/Nestopia and NES:
  • How are you clearing RAM at the start of your program?
  • Are you turning off rendering early? I helped discover a glitch in the OAM refresh while developing Tetramino.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Also be sure you don't have any of the emulators' "reduced accuracy/enhanced visuals" effects enabled. I know that in particular Nestopia has an option that turns off the 8 sprites per scanline limit.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

I first disable graphics, then wait two vblanks, then clear ram in pages $000-$700.

My program is an experiment with displaying meta-sprites. In my current test program, I am displaying two meta sprites. If each meta sprite is composed of 8 sprites (4 wide x2 high), there is no flicker. If each meta sprite is composed of more than this, the sprites begin to flicker. The max size I've tried is two meta sprites which are 4x4 sprites. From what I understood from documentation, this would bring the max sprites per scanline to 8 (if the two meta sprites are positioned next to each other), which is the max allowed for the NES. I assumed when I read that that there would be no flicker...is that incorrect?

*edit* Upon modifying my test programs, when I displayed two 4x4 meta sprites, the flicker did begin to show up in both Nestopia and Nintendulator. There seems to be a small discrepancy between these emulators and the real hardware for when flicker begins occurring (based on no. of sprites)

*edit* I found tepples' post

http://www.nesdev.com/bbs/viewtopic.php ... d1ee7456b4

I am not yet certain if I'm seeing the same problem, though.
User avatar
hap
Posts: 355
Joined: Thu Mar 24, 2005 3:17 pm
Contact:

Post by hap »

I don't think any NES emulator accurately emulates what can happen when writing to the PPU in an active scanline. An easy 'fix' for your program is: vblank NMI -> disable PPU -> upload data to PPU -> enable PPU.

Also, be sure to do a sprite DMA every vblank, as sprite attribute RAM contents may deteriorate if untouched for a while (not sure of this myself). This effect is also not emulated.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

I noticed if I draw a large enough meta sprite (with 28 sprites in nintendulator), my background starts to flicker and scroll vertically (with your suggestion of turning off rendering-> upload to PPU -> turning on rendering). This looks like my rendering is taking longer than vblank. Maybe I should test in PAL mode to confirm this. *edit* sure enough, no problems in pal mode in nintendulator.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

If you haven't implemented a "flicker" routine and all sprites hold the same places in the OAM page every frame, the sprites should not flicker at all. Have you ever played SMB1 and watched one of those pulley-platforms disappear when on the same scanline as another? That's what it should look like. One and only one should completely disappear.

My guess is it's something kind of unnatural, like a PPU glitch. Always be very aware of how long your Vblank code takes. You should count the cycles. If it works in PAL mode like you said, it's very possible this is what's happening.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

I've read on this forum that vblank is over 2000 CPU cycles in length, yet from testing my own programs in nintendulator, I seem to get flicker with the following code: (I have already loaded a background, and in vblank all I do is disable rendering and re-enable it)

Code: Select all

vblank:
  pha ;1
  txa ;1
  pha ;1
  tya ;1
  pha ;1
  php ;1

  ldx #0
  stx $2001    ; disable rendering

  ldx #$ff ;2
- dex      ;1
  bne -    ;2

  ldx #$d3 ;2
  ;ldx #$d4 ;2  ;uncomment this line, you will get flicker
- dex      ;1
  bne -    ;2

  lda #%00011110
  sta $2001


  plp ;1
  pla ;1
  tay ;1
  pla ;1
  tax ;1
  pla ;1

irq:
  rti
I don't know how long it takes to enable/disable rendering, but I put some loops in there which, if I've done my arithmetic right, take 1402 cycles. Where are the remaining 600+ cycles going?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

A taken branch is (usually) 3 cycles, not 2.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

And all instructions take at least two cycles. Looks like you're totaling the number of BYTES each instruction is encoded in, rather than the amount of work it's doing. Here's a more realistic cycle timing:

Code: Select all

vblank:
                ; 14 for previous instruction + vectoring
    pha         ; 3
    txa         ; 2
    pha         ; 3
    tya         ; 2
    pha         ; 3
    php         ; 3

    ldx #0      ; 2
    stx $2001   ; 4 disable rendering

    ldx #$ff    ; 2
-   dex         ; 2
    bne -       ; 3
                ; -1
    ldx #$d3    ; 2
    ;ldx #$d4   ; 2 uncomment this line, you will get flicker
-   dex         ; 2
    bne -       ; 3
                ; -1
    lda #%00011110; 2
    sta $2001   ; 4

    plp         ; 4
    pla         ; 4
    tay         ; 2
    pla         ; 4
    tax         ; 2
    pla         ; 4

    rti         ; 6
I calculate 2293 cycles from NMI to the final STA $2001. Uncommenting that line adds 7 cycles.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

Thank you for the corrections.

Does there exist a good reference for determining how many cpu cycles each instruction takes? I erroneously assumed the number in a certain column in a 6502 reference was the # of cycles, rather than the size of the instruction in memory...my bad.
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

Wow, that was fast. Thanks! :D
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Post by GradualGames »

Thanks to you guys, I've had a leap of understanding about programming for the NES this evening. So, vblank is only around 2000 cycles long, that must mean there's quite a lot more cycles available while the PPU is rendering. Thus, I would imagine game engines are (often, I realize there is more than one way to do this) set up roughly as follows:

Code: Select all

loop:

;wait for frame to begin (perhaps wait for our vblank to end with a simple flag)
 
  ;none of this code will update graphics or sound, just make various game related calculations (which may be quite CPU intensive, thus this is the most appropriate place for them)
  jsr updateAllGameObjectsAndAI

  jmp loop

vblank:

  ;all of these update graphics and sound as calculated by the game engine during the previous frame
  jsr updateSprites        ;sprite DMA
  jsr updateBackground ;scrolling, nametable updates
  jsr updateSound         ;sound and music engine

  ;set a flag so the game engine knows it can do whatever it wants til the next vblank is called

  rti
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

ZomCoder wrote:

Code: Select all

-
  lda $2002
  clc
  rol a
  bcs -
I have never seen anyone poll for $2002 that way before! To me, that's not even a newbie way of doing it; it's more complex than the standard way to do it:

Code: Select all

-
   lda $2002
   bmi -
And besides, you wouldn't need to clear the carry in that loop, as it gets overwritten with the value shifted into it.

I'm pretty sure you're right though about the game loop thing, just it's executed differently (probably with no polling). You never want the game loop to run at more than 60/50 Hz (either NTSC or PAL), and you never want the NMI to update data when its not ready. So that basically means you should have flags and stuff that indicate whether or not the data is ready. Though whether or not this approach is worth the complexity is debatable.
Post Reply