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:
Here's what happens when D0-D1 is set to 1 (erroneously I believe):
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?
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:
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
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:
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
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?