In a trace of SMB3 I came across an interesting piece of code. This was traced while Mario was scrolling to the right in-stage. I noticed that 2006 is written to 4 times in a row without any 2002 read in the middle:
$F51D:AD 02 20 LDA $2002 = #$07 A:00 X:00 Y:00 P:nvUbdIZc
$F520:A9 3F LDA #$3F A:07 X:00 Y:00 P:nvUbdIzc
$F522:8D 06 20 STA $2006 = #$20 A:3F X:00 Y:00 P:nvUbdIzc
$F525:A9 00 LDA #$00 A:3F X:00 Y:00 P:nvUbdIzc
$F527:8D 06 20 STA $2006 = #$20 A:00 X:00 Y:00 P:nvUbdIZc
$F52A:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
$F52D:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
What do y'all think of that?
beneficii wrote:
In a trace of SMB3 I came across an interesting piece of code. This was traced while Mario was scrolling to the right in-stage. I noticed that 2006 is written to 4 times in a row without any 2002 read in the middle:
$F51D:AD 02 20 LDA $2002 = #$07 A:00 X:00 Y:00 P:nvUbdIZc
$F520:A9 3F LDA #$3F A:07 X:00 Y:00 P:nvUbdIzc
$F522:8D 06 20 STA $2006 = #$20 A:3F X:00 Y:00 P:nvUbdIzc
$F525:A9 00 LDA #$00 A:3F X:00 Y:00 P:nvUbdIzc
$F527:8D 06 20 STA $2006 = #$20 A:00 X:00 Y:00 P:nvUbdIZc
$F52A:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
$F52D:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
What do y'all think of that?
Let me write that again. This thing won't let me delete my old post.
Code:
$F51D:AD 02 20 LDA $2002 = #$07 A:00 X:00 Y:00 P:nvUbdIZc
$F520:A9 3F LDA #$3F A:07 X:00 Y:00 P:nvUbdIzc
$F522:8D 06 20 STA $2006 = #$20 A:3F X:00 Y:00 P:nvUbdIzc
$F525:A9 00 LDA #$00 A:3F X:00 Y:00 P:nvUbdIzc
$F527:8D 06 20 STA $2006 = #$20 A:00 X:00 Y:00 P:nvUbdIZc
$F52A:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
$F52D:8D 06 20 STA $2006 = #$00 A:00 X:00 Y:00 P:nvUbdIZc
Writing $3F $00 to $2006 resets the palette pointer. In some cases, when the background is turned off, the PPU will display the color that the palette pointer points to instead of color 0 for the background.
Then writing $00 $00 resets the scroll position to (0, 0) of the $2000 nametable.
Disassemble SMB1 and you'll find the same code.
tepples wrote:
In some cases, when the background is turned off, the PPU will display the color that the palette pointer points to instead of color 0 for the background.
Correct - it does that whenever the VRAM address is pointing at the palette and rendering is turned off.
Quietust wrote:
tepples wrote:
In some cases, when the background is turned off, the PPU will display the color that the palette pointer points to instead of color 0 for the background.
Correct - it does that whenever the VRAM address is pointing at the palette and rendering is turned off.
But the background wasn't off during the part of the game I was tracing. What are the effects if the background is on?
Quietust wrote:
tepples wrote:
In some cases, when the background is turned off, the PPU will display the color that the palette pointer points to instead of color 0 for the background.
Correct - it does that whenever the VRAM address is pointing at the palette and rendering is turned off.
Does this apply to the 8-pixel mask region at the left side? Does it apply when sprite rendering is turned on but BG rendering is turned off?
Quote:
Correct - it does that whenever the VRAM address is pointing at the palette and rendering is turned off.
Wait! So you mean I can turn the screen off and draw stuff just by pointing to the correct palette entry? Thats like drawing pixel by pixel, except it would take longer then one actual pixel to set the pointer... but it is still usefull! Do any emulators implement this? Man, I think this can be VERY usefull if it works like you're saying...
toku wrote:
Quote:
Correct - it does that whenever the VRAM address is pointing at the palette and rendering is turned off.
Wait! So you mean I can turn the screen off and draw stuff just by pointing to the correct palette entry? Thats like drawing pixel by pixel, except it would take longer then one actual pixel to set the pointer... but it is still usefull! Do any emulators implement this? Man, I think this can be VERY usefull if it works like you're saying...
What do you mean, Draw stuff just by pointing to the correct palette entry?
Of course emulators have implemented this. This is done in SMB3.
beneficii wrote:
What do you mean, Draw stuff just by pointing to the correct palette entry?
Of course emulators have implemented this. This is done in SMB3.
Uhh, no it isn't. Very few emulators (my emulator being one of them) implement turning rendering off and pointing the VRAM address at the palette to draw specific colors on the screen.
Quietust wrote:
beneficii wrote:
What do you mean, Draw stuff just by pointing to the correct palette entry?
Of course emulators have implemented this. This is done in SMB3.
Uhh, no it isn't. Very few emulators (my emulator being one of them) implement turning rendering off and pointing the VRAM address at the palette to draw specific colors on the screen.
What's your emulator called?
My emulator is called
Nintendulator and can be found at
http://nintendulator.sourceforge.net/
Quietust wrote:
My emulator is called
Nintendulator and can be found at
http://nintendulator.sourceforge.net/
Oh, I have that emulator. It's pretty accurate, but it's fairly slow (perhaps because I have a 366mHz processor computer?).
beneficii wrote:
What do you mean, Draw stuff just by pointing to the correct palette entry?
Of course emulators have implemented this. This is done in SMB3.
I meant we could draw things to the screen by turning the BG off and change $2006 at hte right times to point to wichever color we want to draw.
Not that obvious as you can see... just because SMB3 runs it doesn't mean it runs perfectly, and the missemulation of this feature might go unnoticed pretty easily...
I think this is great... I was a little upset because I thought color 0 would always be on screen whenever the BG was turned off, so, for me, this is great news.
Why didn't anyone document this before? I've seen discussions about this topic and people always said color 0 would be drawn.
Well, I'm just glad I got to know this! Thanks guys!
-tokumaru-
Do you have any plans to add a full screen mode and/or vsync?
Maybe a scan line option? (25/50/100%)
Yeah, I never bought color 0 being drawn, because I've seen the screen turned off myself and in one emulator it's always grey when the screen is off.
Oh, so this keeps the screen a particular color when it is turned off?
toku wrote:
beneficii wrote:
What do you mean, Draw stuff just by pointing to the correct palette entry?
Of course emulators have implemented this. This is done in SMB3.
I meant we could draw things to the screen by turning the BG off and change $2006 at hte right times to point to wichever color we want to draw.
Not that obvious as you can see... just because SMB3 runs it doesn't mean it runs perfectly, and the missemulation of this feature might go unnoticed pretty easily...
I think this is great... I was a little upset because I thought color 0 would always be on screen whenever the BG was turned off, so, for me, this is great news.
Why didn't anyone document this before? I've seen discussions about this topic and people always said color 0 would be drawn.
Well, I'm just glad I got to know this! Thanks guys!
-tokumaru-
Rule of thumb: Ninety-plus percent of the time, Nintendulator is correct.
I wrote some code to change the VRAM address to various palette entries and it does change the background color when the PPU is disabled. The palette was filled with $20-$3f.
Code:
loop2: jsr wait_nmi ; wait until nmi interrupt occurs
jsr wait_vbl ; wait until vbl flag is set
ldy #$60 ; change ppu addr this many times total
lda #0
loop:
ldx #50 ; delay 250 cycles
delay: dex
bne delay
ldx #$3f ; ppu addr = $3f00+A
stx $2006
sta $2006
adc #1 ; loop within $20 range
and #$1f
dey
bne loop
jmp loop2
The second version simply changes palette entry 0 repeatedly. To avoid graphical glitches I encountered due to the VRAM address momentarily being $3f01 due to auto-increment after writing to $3f00, I change the increment to 32 so it steps out of the palette.
Code:
loop2: jsr wait_nmi ; wait until nmi interrupt occurs
jsr wait_vbl ; wait until vbl flag is set
lda #$84 ; addr increment = 32
sta $2000
ldy #$60 ; change ppu addr this many times total
lda #0
loop:
ldx #50 ; delay 250 cycles
delay: dex
bne delay
ldx #$3f ; change palette entry 0
stx $2006
ldx #$00
stx $2006
sta $2007
adc #1 ; loop within $40 range
and #$3f
dey
bne loop
jmp loop2
You didn't need to do 4 writes?
The code I pasted is what I ran. It sets the address only once. Why would it need to do four writes to $2006? I guess it doesn't really matter because the second test showed that you can change the background color palette entry directly (giving you access to all colors), rather than only change which palette entry it uses for the background color.
A side note: wait_nmi is called only keep it synchronized with the refresh, otherwise the pattern constantly moves and is harder to do a video capture of.
blargg wrote:
I wrote some code to change the VRAM address to various palette entries and it does change the background color when the PPU is disabled. The palette was filled with $20-$3f.
The second version simply changes palette entry 0 repeatedly. To avoid graphical glitches I encountered due to the VRAM address momentarily being $3f01 due to auto-increment after writing to $3f00, I change the increment to 32 so it steps out of the palette.
These look very atari 2600'ish, wich is cool. If the color changing was aligned with the hblanks it would look even cooler.
Having access to all NES colors is a very good thing. Now, how short could the "pixels" be by using these methods?... 1 CPU cycle is like, 3 pixels long, right? Supposing no loop is used, only consecutive writes to memory (what would require a lot of space in ROM)... well, I guess we're better off using lines than pseudo-pixels with this...
Can we keep the sprites on and still use this BG trick? We could have some really cool effects like this...
Sprites can NOT be used with that trick, since enabling sprites will turn on rendering, forcing the screen background to be palette[0] (i.e. the value at PPU $3F00, NOT the gray color 0x00) .
wait.. so... ANY palette color can be the BG color when the screen is off? I was under the impression it could only be $3F00, $3F04, $3F08, or $3F0C. I tried implimenting it both ways and Micro Machines (as well as other games which rely on this trick) don't work when I allow any color to be the BG.
Yes, ANY color can be used within $3F00-$3F1F (though $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C).
It's working fine here with any colour, a good test for this, next to Micro Machines of course, is Loopy's paltest.nes where you can see lines gradually going to white, then to black.
I improved the two demos. They are now cycle-timed to synchronize with horizontal scanlines. I also rewrote them for nesasm to make them easier for others to use. The archive has the asm source, NES ROMs, and video captures. I can't run Nintendulator so let me know if the NES ROMs don't work.
ppu_off_colors2.zip
One makes a rainbow of horizontal bars down the screen by cycling palette entry 0 through all available colors. The downside of this technique is that changing the color requires 12 cycles at minimum.
The other makes a rainbow of vertical bars across the screen by cycling through different palette addresses. At the core it reads from $2007 several times in a row, the fastest way I could come up with. The downside of this technique is that it uses several palette entries.
Code:
draw_band:
ldx #$3f ; start at palette entry 0
stx $2006
ldx #$00
stx $2006
ldx $2007 ; quickly increment vram address
ldx $2007 ; to cycle through each color
ldx $2007
ldx $2007
; etc.
It's working fine.
Kind of off-topic: Judging from the pic of vert_bands.nes, it's supposed to shake a bit. My emulator is doing it like this (x position guessed):
40, 36, 39, 35, 38, 34, 37, 40, etc.
Nintendulator (probably correct?): 40, 36, 40, 36, 40, 36, etc.
Yeah, I haven't studied the NES PPU much and didn't know the exact frame times, so I couldn't eliminate the horizontal jitter. The first sequence you posted looks more correct; it's definitely toggling horizontally several pixels each 1/60 frame, and overall moving to the left every two frames, resetting back to its original position several times a second. This is due to 0, 1, or 2 cycle latency in NMI acknowledgement, and that the total PPU frame time seems to hace a fraction of a CPU cycle (and probably two different values for odd and even fields, ugh).
A very tangential test of an emulator, if I say so :)
Sorry, my fault: I had the odd/even fields implementation commented out (scanline 20 being 340 cycles instead of 341 every odd frame as stated in Brad Taylor's doc).
So without it, your demo will behave as the first sequence, and with it, as the 2nd. If normal behaviour is as the 1st sequence, it suggests that that feature is not available on your NES, hmm..