New emu: SMB status bar flashes when scrolling

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

New emu: SMB status bar flashes when scrolling

Post by pops » Sun Apr 04, 2010 4:51 pm

I've been putting together my first emulator over the past week. So far I have SMB working just about right... except that the status bar flashes on and off when scrolling.

I know that the status bar is maintained in the $2000 name table, and when scrolling, the game uses $2400 as well, necessitating the sprite0 flag check at scanline 30-31 or so. On VINT, the SMB rom sets the name table address flag (D1-D0 of $2000) to 0, and then sets it back to 1 after sprite0.

But half of the time the game almost immediately after setting D1-D0 to 0, sets it to 1 again.

The difference between setting it to 0 and exiting, and resetting it to 1 (which happens twice(!) sometimes) is a BNE check at $8EE4; this should, I believe, not branch when the code is executing correctly.

Key:
+1: PC + 1
+2: PC + 2
$0: Mem @ $0000
$1: Mem @ $0001

Here's what happen's when D0-D1 is set once, to 0:

Code: Select all

PC__  OP_____________________           +1 +2 A_ X_ Y_ SP P_ $0 R1
80C3  20  JSR                           DD 8E 03 00 00 FC 09 01 03
8EDD  AE  LDX_Absolute                  02 20 03 00 00 FA 09 01 03
8EE0  A0  LDY_Immediate                 00 B1 03 00 00 FA 0B 01 03
8EE2  B1  LDA_IndirectY                 00 D0 03 00 00 FA 0B 01 03
*** SCANLINE 243                        D0 AC 00 00 00 FA 0B 01 03
8EE4  D0  BNE                           AC 8D 00 00 00 FA 0B 01 03
8EE6  8D  STA_Absolute                  05 20 00 00 00 FA 0B 01 03
8EE9  8D  STA_Absolute                  05 20 00 00 00 FA 0B 01 03
8EEC  60  RTS                           8D 00 00 00 00 FA 0B 01 03
Here's what happens when D0-D1 is set to 1 (erroneously I believe):

Code: Select all

PC__  OP_____________________           +1 +2 A_ X_ Y_ SP P_ $0 R1
80C3  20  JSR                           DD 8E 03 00 00 FC 09 01 03  ;update screen with buffer contents
8EDD  AE  LDX_Absolute                  02 20 03 00 00 FA 09 01 03  ;reset flip-flop
8EE0  A0  LDY_Immediate                 00 B1 03 00 00 FA 0B 01 03  ;load first byte from indirect as a pointer
8EE2  B1  LDA_IndirectY                 00 D0 03 00 00 FA 0B 01 03  
*** SCANLINE 243                        D0 AC 3F 00 00 FA 09 01 03
8EE4  D0  BNE                           AC 8D 3F 00 00 FA 09 01 03  ;if byte is zero we have no further updates to make here
8E92  8D  STA_Absolute                  06 20 3F 00 00 FA 09 01 03  ;store high byte of vram address
8E95  C8  INY                           B1 00 3F 00 00 FA 09 01 03
8E96  B1  LDA_IndirectY                 00 8D 3F 00 01 FA 09 01 03  ;load next byte (second)
8E98  8D  STA_Absolute                  06 20 0C 00 01 FA 09 01 03  ;store low byte of vram address
8E9B  C8  INY                           B1 00 0C 00 01 FA 09 01 03  
8E9C  B1  LDA_IndirectY                 00 0A 0C 00 02 FA 09 01 03  ;load next byte (third)
8E9E  0A  ASL_Accumulator               48 AD 04 00 02 FA 09 01 03  ;shift to left and save in stack
8E9F  48  PHA                           AD 78 08 00 02 FA 08 01 03
8EA0  AD  LDA_Absolute                  78 07 08 00 02 F9 08 01 03  ;load mirror of $2000,
8EA3  09  ORA_Immediate                 04 B0 11 00 02 F9 08 01 03  ;set ppu to increment by 32 by default
8EA5  B0  BCS                           02 29 15 00 02 F9 08 01 03  ;if d7 of third byte was clear, ppu will
8EA7  29  AND_Immediate                 FB 20 15 00 02 F9 08 01 03  ;only increment by 1
8EA9  20  JSR                           ED 8E 11 00 02 F9 08 01 03  ;write to register
8EED  8D  STA_Absolute                  00 20 11 00 02 F7 08 01 03
PPU.4000 : 17                           8D 78 11 00 02 F7 08 01 03
I've been staring this error down for a couple of hours now - it's the first major stumbling block I've run up against, and I have no idea what's going wrong. Could someone give me a hint as to what I'm doing wrong?
Last edited by pops on Sun Apr 04, 2010 5:14 pm, edited 1 time in total.

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Sun Apr 04, 2010 5:04 pm

it might help if your tracer printed what address the CPU was reading/writing instead of just the instruction and addressing mode. As it is now, the tracer doesn't really do much of a job of illustrating what's going on.

Where are the $2000 writes in this code?

I assume those columns on the right are A,X,Y, but which is which?

pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Post by pops » Sun Apr 04, 2010 5:17 pm

Disch wrote:it might help if your tracer printed what address the CPU was reading/writing instead of just the instruction and addressing mode. As it is now, the tracer doesn't really do much of a job of illustrating what's going on.

Where are the $2000 writes in this code?

I assume those columns on the right are A,X,Y, but which is which?
My bad, I forgot a key. The values are +1, +2, A, X, Y, SP, P, $0, $1.
+1: PC + 1
+2: PC + 2
$0: Mem @ $0000
$1: Mem @ $0001

So the second instruction, LDX_Absolute 02 20 loads $2002 into X.

I'll work on better tracer output, but for the moment, this is what I have. :)

Here's better output. Key is: last mem address accessed, last mem value, a, x, y, sp, p. I've indicated ppu address writes to $2000 with "PPU.4000 : value" (which appear before the instructions in the traced code.
Correct:

Code: Select all

*** SCANLINE 242                        8059 80    91 0D D0 FF 89
8082  AD  LDA_Absolute                  0778 11    11 0D D0 FC 09
8085  29  AND_Immediate                 8086 7F    11 0D D0 FC 09
8087  8D  STA_Absolute                  0778 11    11 0D D0 FC 09
808A  29  AND_Immediate                 808B 7E    10 0D D0 FC 09
PPU.4000 : 16                           2000 10    10 0D D0 FC 09
808C  8D  STA_Absolute                  2000 10    10 0D D0 FC 09
808F  AD  LDA_Absolute                  0779 1E    1E 0D D0 FC 09
8092  29  AND_Immediate                 8093 E6    06 0D D0 FC 09
8094  AC  LDY_Absolute                  0774 00    06 0D 00 FC 0B
8097  D0  BNE                           8097 D0    06 0D 00 FC 0B
8099  AD  LDA_Absolute                  0779 1E    1E 0D 00 FC 09
809C  09  ORA_Immediate                 809D 1E    1E 0D 00 FC 09
809E  8D  STA_Absolute                  0779 1E    1E 0D 00 FC 09
80A1  29  AND_Immediate                 80A2 E7    06 0D 00 FC 09
80A3  8D  STA_Absolute                  2001 06    06 0D 00 FC 09
80A6  AE  LDX_Absolute                  2002 80    06 80 00 FC 89
80A9  A9  LDA_Immediate                 80AA 00    00 80 00 FC 0B
80AB  20  JSR                           01FB AD    00 80 00 FA 0B
8EE6  8D  STA_Absolute                  2005 00    00 80 00 FA 0B
8EE9  8D  STA_Absolute                  2005 00    00 80 00 FA 0B
8EEC  60  RTS                           01FC 80    00 80 00 FC 0B
80AE  8D  STA_Absolute                  2003 00    00 80 00 FC 0B
80B1  A9  LDA_Immediate                 80B2 02    02 80 00 FC 09
80B3  8D  STA_Absolute                  4014 02    02 80 00 FC 09
80B6  AE  LDX_Absolute                  0773 00    02 00 00 FC 0B
80B9  BD  LDA_AbsoluteX                 805A 01    01 00 00 FC 09
80BC  85  STA_ZeroPage                  0000 01    01 00 00 FC 09
80BE  BD  LDA_AbsoluteX                 806D 03    03 00 00 FC 09
80C1  85  STA_ZeroPage                  0001 03    03 00 00 FC 09
80C3  20  JSR                           01FB C5    03 00 00 FA 09
8EDD  AE  LDX_Absolute                  2002 00    03 00 00 FA 0B
8EE0  A0  LDY_Immediate                 8EE1 00    03 00 00 FA 0B
8EE2  B1  LDA_IndirectY                 0301 00    00 00 00 FA 0B
*** SCANLINE 243                        0301 00    00 00 00 FA 0B
8EE4  D0  BNE                           8EE4 D0    00 00 00 FA 0B
8EE6  8D  STA_Absolute                  2005 00    00 00 00 FA 0B
8EE9  8D  STA_Absolute                  2005 00    00 00 00 FA 0B
8EEC  60  RTS                           01FC 80    00 00 00 FC 0B
Incorrect:

Code: Select all

8082  AD  LDA_Absolute                  0778 11    11 05 04 FC 09
8085  29  AND_Immediate                 8086 7F    11 05 04 FC 09
8087  8D  STA_Absolute                  0778 11    11 05 04 FC 09
808A  29  AND_Immediate                 808B 7E    10 05 04 FC 09
PPU.4000 : 16                           2000 10    10 05 04 FC 09
808C  8D  STA_Absolute                  2000 10    10 05 04 FC 09
808F  AD  LDA_Absolute                  0779 1E    1E 05 04 FC 09
8092  29  AND_Immediate                 8093 E6    06 05 04 FC 09
8094  AC  LDY_Absolute                  0774 00    06 05 00 FC 0B
8097  D0  BNE                           8097 D0    06 05 00 FC 0B
8099  AD  LDA_Absolute                  0779 1E    1E 05 00 FC 09
809C  09  ORA_Immediate                 809D 1E    1E 05 00 FC 09
809E  8D  STA_Absolute                  0779 1E    1E 05 00 FC 09
80A1  29  AND_Immediate                 80A2 E7    06 05 00 FC 09
80A3  8D  STA_Absolute                  2001 06    06 05 00 FC 09
80A6  AE  LDX_Absolute                  2002 80    06 80 00 FC 89
80A9  A9  LDA_Immediate                 80AA 00    00 80 00 FC 0B
80AB  20  JSR                           01FB AD    00 80 00 FA 0B
8EE6  8D  STA_Absolute                  2005 00    00 80 00 FA 0B
8EE9  8D  STA_Absolute                  2005 00    00 80 00 FA 0B
8EEC  60  RTS                           01FC 80    00 80 00 FC 0B
80AE  8D  STA_Absolute                  2003 00    00 80 00 FC 0B
80B1  A9  LDA_Immediate                 80B2 02    02 80 00 FC 09
80B3  8D  STA_Absolute                  4014 02    02 80 00 FC 09
80B6  AE  LDX_Absolute                  0773 00    02 00 00 FC 0B
80B9  BD  LDA_AbsoluteX                 805A 01    01 00 00 FC 09
80BC  85  STA_ZeroPage                  0000 01    01 00 00 FC 09
80BE  BD  LDA_AbsoluteX                 806D 03    03 00 00 FC 09
80C1  85  STA_ZeroPage                  0001 03    03 00 00 FC 09
80C3  20  JSR                           01FB C5    03 00 00 FA 09
8EDD  AE  LDX_Absolute                  2002 00    03 00 00 FA 0B
8EE0  A0  LDY_Immediate                 8EE1 00    03 00 00 FA 0B
8EE2  B1  LDA_IndirectY                 0301 3F    3F 00 00 FA 09
*** SCANLINE 243                        0301 3F    3F 00 00 FA 09
8EE4  D0  BNE                           8EE5 AC    3F 00 00 FA 09
8E92  8D  STA_Absolute                  2006 3F    3F 00 00 FA 09
8E95  C8  INY                           8E95 C8    3F 00 01 FA 09
8E96  B1  LDA_IndirectY                 0302 0C    0C 00 01 FA 09
8E98  8D  STA_Absolute                  2006 0C    0C 00 01 FA 09
8E9B  C8  INY                           8E9B C8    0C 00 02 FA 09
8E9C  B1  LDA_IndirectY                 0303 04    04 00 02 FA 09
8E9E  0A  ASL_Accumulator               8E9E 0A    08 00 02 FA 08
8E9F  48  PHA                           01FA 08    08 00 02 F9 08
8EA0  AD  LDA_Absolute                  0778 11    11 00 02 F9 08
8EA3  09  ORA_Immediate                 8EA4 04    15 00 02 F9 08
8EA5  B0  BCS                           8EA5 B0    15 00 02 F9 08
8EA7  29  AND_Immediate                 8EA8 FB    11 00 02 F9 08
8EA9  20  JSR                           01F8 AB    11 00 02 F7 08
PPU.4000 : 17                           2000 11    11 00 02 F7 08
8EED  8D  STA_Absolute                  2000 11    11 00 02 F7 08
8EF0  8D  STA_Absolute                  0778 11    11 00 02 F7 08
8EF3  60  RTS                           01F9 8E    11 00 02 F9 08

User avatar
Zepper
Formerly Fx3
Posts: 3223
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Sun Apr 04, 2010 6:17 pm

- This isn't an human-friendly readable disassembled code.

NickMass
Posts: 15
Joined: Tue Mar 30, 2010 7:59 pm

Post by NickMass » Sun Apr 04, 2010 6:46 pm

The emulator I've been working on has exactly the same issue with the blinking status bar, and it seems my tracer output is identical but a bit more verbose, here's what mine outputs if it can help diagnose what is going on.

Correct:
http://nickmass.com/emu/correct.txt

Incorrect:
http://nickmass.com/emu/incorrect.txt

pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Post by pops » Sun Apr 04, 2010 6:57 pm

Zepper wrote:- This isn't an human-friendly readable disassembled code.
Apologies for that.

NickMass, your output and mine both have the same problem: instruction $8EE2 reads from $0301, which should be zero. If it is non-zero, then this bug appears (I've noticed values $3F and $26 in $0301, although certainly other values may be possible).

This value is loaded at $8AF5 ($26) and $89F2 ($3F).

Per the smb disassembly (at http://www.romhacking.net/docs/344/), the routines at these two addresses are ColorRotation and MushroomIconData

$89F2

Code: Select all

ColorRotation:
              lda FrameCounter         ;get frame counter
              and #$07                 ;mask out all but three LSB
              bne ExitColorRot         ;branch if not set to zero to do this every eighth frame
              ldx VRAM_Buffer1_Offset  ;check vram buffer offset
              cpx #$31
              bcs ExitColorRot         ;if offset over 48 bytes, branch to leave
              tay                      ;otherwise use frame counter's 3 LSB as offset here
GetBlankPal:  lda BlankPalette,y       ;get blank palette for palette 3
              sta VRAM_Buffer1,x       ;store it in the vram buffer *** WRITE TO 0301
              inx                      ;increment offsets
              iny
              cpy #$08
              bcc GetBlankPal          ;do this until all bytes are copied
              ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
              lda #$03
              sta $00                  ;set counter here
              lda AreaType             ;get area type
              asl                      ;multiply by 4 to get proper offset
              asl
              tay                      ;save as offset here
GetAreaPal:   lda Palette3Data,y       ;fetch palette to be written based on area type
              sta VRAM_Buffer1+3,x     ;store it to overwrite blank palette in vram buffer
              iny
              inx
              dec $00                  ;decrement counter
              bpl GetAreaPal           ;do this until the palette is all copied
              ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
              ldy ColorRotateOffset    ;get color cycling offset
              lda ColorRotatePalette,y
              sta VRAM_Buffer1+4,x     ;get and store current color in second slot of palette
              lda VRAM_Buffer1_Offset
              clc                      ;add seven bytes to vram buffer offset
              adc #$07
              sta VRAM_Buffer1_Offset
              inc ColorRotateOffset    ;increment color cycling offset
              lda ColorRotateOffset
              cmp #$06                 ;check to see if it's still in range
              bcc ExitColorRot         ;if so, branch to leave
              lda #$00
              sta ColorRotateOffset    ;otherwise, init to keep it in range
ExitColorRot: rts                      ;leave
$8AF5:

Code: Select all

MushroomIconData:
      .db $07, $22, $49, $83, $ce, $24, $24, $00

DrawMushroomIcon:
              ldy #$07                ;read eight bytes to be read by transfer routine
IconDataRead: lda MushroomIconData,y  ;note that the default position is set for a
              sta VRAM_Buffer1-1,y    ;1-player game *** WRITE TO 0301
              dey
              bpl IconDataRead
              lda NumberOfPlayers     ;check number of players
              beq ExitIcon            ;if set to 1-player game, we're done
              lda #$24                ;otherwise, load blank tile in 1-player position
              sta VRAM_Buffer1+3
              lda #$ce                ;then load shroom icon tile in 2-player position
              sta VRAM_Buffer1+5
ExitIcon:     rts
[edit]
Memory location 0301 is set to zero again at instruction $80D8... which is after the offending branch. I don't think it's reset anywhere else...

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Sun Apr 04, 2010 9:26 pm

I think I figured it out guys.

The "incorrect" code is really correct. What's going on is the game is writing new map data. I'm guessing the screen is flickering when the screen scrolls, right? As in new data is being drawn.

The game may not write to $2000 after drawing, but from looking at the smb disassembly, it DOES zero $2006. See my notes at the beginning and end of this code snippit:

Code: Select all

;;**
;; HERE IS THE PROBLEM JSR TO THE CODE THAT WRITES TO $2000
;;**

SetupWrites:   jsr WritePPUReg1          ;write to register
               pla                       ;pull from stack and shift to left again
               asl
               bcc GetLength             ;if d6 of third byte was clear, do not repeat byte
               ora #%00000010            ;otherwise set d1 and increment Y
               iny
GetLength:     lsr                       ;shift back to the right to get proper length
               lsr                       ;note that d1 will now be in carry
               tax
OutputToVRAM:  bcs RepeatByte            ;if carry set, repeat loading the same byte
               iny                       ;otherwise increment Y to load next byte
RepeatByte:    lda ($00),y               ;load more data from buffer and write to vram
               sta PPU_DATA
               dex                       ;done writing?
               bne OutputToVRAM
               sec          
               tya
               adc $00                   ;add end length plus one to the indirect at $00
               sta $00                   ;to allow this routine to read another set of updates
               lda #$00
               adc $01
               sta $01
               lda #$3f                  ;sets vram address to $3f00
               sta PPU_ADDRESS
               lda #$00
               sta PPU_ADDRESS
               sta PPU_ADDRESS           ;then reinitializes it for some reason
               sta PPU_ADDRESS
;;**
;; THE ABOVE STA'S CLEAR $2006
;;**
You guys must not be doing the scrolling properly. Remember that $2006, $2005, and the low 2 bits of $2000 all change the same register ("loopy_t"). So by writing zero to $2006 twice, the low 2 bits of $2000 are effectively zero'd as well.


Edit: wtf @ double line breaks

pops
Posts: 91
Joined: Sun Apr 04, 2010 4:28 pm

Post by pops » Sun Apr 04, 2010 10:02 pm

Your solution worked perfectly Disch. I really appreciate your help.

I hacked your solution into my emulator so that if VRAM_Address = 0 after $2006 is written to with the latch set, I clear the Name table base address (D1-D0 of $2000)... and while this works perfectly for SMB, I should obviously look into emulating loopy_t. So I'll be diving into http://h1.ripway.com/blargg/temp/nes_ppu_scrolling.txt tomorrow. :)

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Sun Apr 04, 2010 10:06 pm

Yeah that page you linked outlines exactly what you need to do.

Glad I could help =)

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

Post by tepples » Mon Apr 05, 2010 4:36 am

Disch wrote:Edit: wtf @ double line breaks
I get this too on GNOME when I copy a Windows-line-ending text file from Gedit to Firefox.

Post Reply