Simple vertical scrolling with status bar

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Simple vertical scrolling with status bar

Post by DRW »

I experimented a bit with vertical scrolling and a status bar, but it doesn't seem to work the way I expected it.

At first the standard code for horizontal scrolling with a sprite 0 split:

Code: Select all

; Set scrolling 0 and name table 0
; for the status bar.
LDA #0
STA PpuScroll
STA PpuScroll
LDA #%10010000
STA PpuCtrl

; Wait for sprite 0.
; (Done as a macro.)
WAIT_FOR_PPU_STATUS %01000000

; Set the scrolling position
; and name table for the level.
LDA scrollingPosition
STA PpuScroll
LDA #0
STA PpuScroll
LDA #%10010000
ORA nameTable
STA PpuCtrl
This one works correctly.

Now, I changed the scrolling position code to the following:

Code: Select all

LDA scrollingPosition
STA PpuScroll
LDA #64
STA PpuScroll
Now, I expected the screen below the status bar to be shifted by 64 pixels.
I.e. if the left image is the regular screen, then one with a vertical scrolling of 64 would be the right image:
Example.PNG
Example.PNG (8.16 KiB) Viewed 4927 times
But the screen still looks like the left image.

It works fine if I set vertical scrolling right away, but when I try to change the scrolling position after the sprite 0 split, i.e. in the middle of the screen, it doesn't work.

Why is that the case? Why can horizontal scrolling be changed in the middle of the screen, but vertical scrolling cannot the way I tried it?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Simple vertical scrolling with status bar

Post by tokumaru »

The vertical scroll can't be changed mid-screen through normal means, because of the way the PPU renders the screen. The scroll register, $2005, only affects the temporary VRAM address register, and parts of this register are copied to the actual VRAM address at key moments. At the beginning of the picture, everything is copied, but during rendering, only the X component is copied every scanline, so that the PPU can start each scanline from the left. The Y coordinate is only incremented from the initial value during the whole picture, which is why changing the temporary VRAM address does nothing.

To force a VRAM address update, you have to write to $2006. If you only need to "snap" to whole tiles, which is probably the case with a status bar, 2 $2006 writes will do, but if you need pixel-perfect precision you might need the infamous $2006/5/5/6 trick.

The layout of the bits for the $2006 writes is:

Code: Select all

76543210
*yyyNNYY (first write)
YYYXXXXX (second write)

XXXXX - coarse X scroll
YYYYY - coarse Y scroll
NN - name table
yyy - fine Y scroll
Note that the fine X scroll is stored somewhere else, so you still need a $2005 write if you want to change it.

The need for combining $2006 and $2005 writes for pixel-perfect scrolling arises from the fact that the highest bit of the fine Y scroll is automatically cleared by the PPU on the first write to $2006, so the only way to set it by using a $2006/5/5/6 sequence. Only on the final $2006 write the VRAM address register is changed.

EDIT: This is what the "The skinny on NES scrolling" document is all about. It describes how and when the temporary VRAM register and the actual VRAM register are changed.
Last edited by tokumaru on Sun Jan 08, 2017 2:38 pm, edited 1 time in total.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Simple vertical scrolling with status bar

Post by DRW »

Alright, looks like it's not a mundane issue and I need to do some more research.

Which specific technique did "The Legend of Zelda" use when the screen scrolls vertically while the status bar remains in place?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Simple vertical scrolling with status bar

Post by koitsu »

I believe Zelda 1 uses a combination of switching to single-screen mirroring (since it uses MMC1) and some of what tokumaru described above. It doesn't appear to use sprite 0 hit (just in case someone brings that up -- I checked in NO$NES).

http://wiki.nesdev.com/w/index.php/List ... _technique
Last edited by koitsu on Sun Jan 08, 2017 3:16 pm, edited 1 time in total.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Simple vertical scrolling with status bar

Post by tepples »

From how to split:
  1. .... NN.. Write nametable number << 2 (that is: $00, $04, $08, or $0C) to $2006
  2. YYYY Yyyy Write Y position to $2005
  3. XXXX Xxxx Write X position to $2005
  4. YYYX XXXX Write low byte of nametable address to $2006, which is ((Y & $F8) << 2) | (X >> 3)
Writes 3 and 4 must happen in horizontal blanking between X=256 and X=320.

Given 9-bit X and Y positions (or nametable number and 8-bit X and Y positions), this code fragment by tokumaru calculates the appropriate values to write.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Simple vertical scrolling with status bar

Post by DRW »

koitsu wrote:I believe Zelda 1 uses a combination of switching to single-screen mirroring (since it uses MMC1) and some of what tokumaru described above.
Yeah, I noticed the mirror switching. This one is a good general way to do horizontal and vertical scrolling in the same game, so that you don't have to fiddle around with graphical artifacts. But the mirror switching is still unrelated to the status bar tricks, so yeah, that particular issue is still done with those other methods.

Thanks for your help. I'll have to see whether I do further research for this or whether I simply use a small status bar created from sprites or whether I simply disable rendering during a screen switch.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Simple vertical scrolling with status bar

Post by tokumaru »

DRW, there's no need to be scared off by this. Since the status bar is always in the same place, you don't even need to calculate the values to write in real time, you can simply use hardcoded values and that's it.

For example, to set the scroll to (0, 200) in NT 0:

1- write %****00** to $2006 (name table);
2- write %11001000 to $2005 (Y scroll);
3- write %00000000 to $2005 (X scroll);
4- write %00100000 (coarse X scroll, lower 3 bits of coarse Y scroll;

Just do this instead of the $2005+$2005+$2000 writes you currently have, and make sure that writes 3 and 4 happen during hblank, to completely avoid glitches.
User avatar
Quietust
Posts: 1918
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Simple vertical scrolling with status bar

Post by Quietust »

If you're doing vertical scrolling with a status bar, there are basically 3 possibilities:
1. Status bar is at the bottom - you do a 6-6-5 write at the split point (6-6 to set render location, 5 to set fine X scroll)
2. Status bar is at the top, and you have a 4 scanline gap below it - for fine Y scroll of 0-3, you do a 6-6-5 write at the bottom of the gap, and for fine Y scroll of 4-7 you do a 6-6-5 write at the top of the gap.
3. Status bar is at the top, and you have no gap - you do a 6-5-5-6 write at the split point

Most games used technique #1 (SMB3, Startropics) or #2 (Castlevania 3, Battletoads) - technique #3 wasn't really known until we discovered it.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
dougeff
Posts: 3078
Joined: Fri May 08, 2015 7:17 pm

Re: Simple vertical scrolling with status bar

Post by dougeff »

Forget 'how does zelda do x'. How does Cosmic Epsilon do this? I mean look at this nametable. WTF.
Attachments
COSMIC.png
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Simple vertical scrolling with status bar

Post by tokumaru »

dougeff wrote:How does Cosmic Epsilon do this? I mean look at this nametable. WTF.
It has pattern table layouts for different setups of lines coming from the horizon towards the screen, and bankswitches between them several times mid-screen to create vertical detail, and changes the split points over time to create movement. It also changes the horizontal scroll several times when moving the screen sideways, but I'm not sure whether it touches the vertical scroll.

EDIT: Your debugger is configured to display the state of the PPU on scanline 200, which happens to be the last pattern you're seeing on the screen (big cyan stripe on the left, blue on the right), but if you change it to show the state on previous scanlines you'll see each one of the stripe configurations at a time.
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Simple vertical scrolling with status bar

Post by Bregalad »

Quietust wrote:If you're doing vertical scrolling with a status bar, there are basically 3 possibilities:
1. Status bar is at the bottom - you do a 6-6-5 write at the split point (6-6 to set render location, 5 to set fine X scroll)
2. Status bar is at the top, and you have a 4 scanline gap below it - for fine Y scroll of 0-3, you do a 6-6-5 write at the bottom of the gap, and for fine Y scroll of 4-7 you do a 6-6-5 write at the top of the gap.
3. Status bar is at the top, and you have no gap - you do a 6-5-5-6 write at the split point

Most games used technique #1 (SMB3, Startropics) or #2 (Castlevania 3, Battletoads) - technique #3 wasn't really known until we discovered it.
Correct, but I'll also mention technique #2b, my favorite, which is the same but uses a 8 scanline gap. You simply do a 6-6-5 write within the gap depending on the fine scroll. Also for both technique 2 and 2b you need to disable background explicitly via $2001 (or via CHR-ROM switch to blank tiles) until the end of the gap.

In addition to that, you can also have one extra pixel of fine scrolling depending on whether the 6-6-5 write is done at the end of the scanline or at the start, so it's possible to have fine-scolling over 5 positions, so it's possible to have only a 3-scanline gap.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Simple vertical scrolling with status bar

Post by tokumaru »

Bregalad wrote:You simply do a 6-6-5 write within the gap depending on the fine scroll. Also for both technique 2 and 2b you need to disable background explicitly via $2001 (or via CHR-ROM switch to blank tiles) until the end of the gap.
Why would you choose to have a mandatory 8 scanline gap, and the added complications of varying the timing and masking the background, while you could just use the 6-5-5-6 sequence instead and have pixel-perfect precision with none of that extra complication?
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Simple vertical scrolling with status bar

Post by Bregalad »

tokumaru wrote: Why would you choose to have a mandatory 8 scanline gap, and the added complications of varying the timing and masking the background
Well for most status bars to look good you neede a gap anyway and because the NES is a tiled system a 8-scanline (that is a 1 tile row) gap comes naturally. What you refer to as extra complexity is actually very simple, something like 4 instructions in assembly.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Simple vertical scrolling with status bar

Post by tokumaru »

The extra complexity is in timing the actual scroll change, which can happen in any one of 8 scanlines, while with the 6-5-5-6 method you can just split at a constant point, because you have full control over the fine vertical scroll. The 6-6-5 method requires a blank area (which is optional with the other method) more PPU writes, more timed code, and offers no advantage at all.
User avatar
Dwedit
Posts: 4921
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Simple vertical scrolling with status bar

Post by Dwedit »

Do you want pure vertical scrolling only, with no horizontal scrolling at all?
If so, you can use the nametable arrangement found in Super Mario 3's vertical scrolling stages:
mario3_vertical.png
mario3_vertical.png (1.28 KiB) Viewed 4717 times
It's vertical mirroring, but with the second nametable used exclusively for the status bar. There are no scrolling glitches on the left nametable since the status bar hides them.

Some other games use single screen mirroring and switch the nametable when switching to the status bar. Still other games simulate single screen mirroring with IRQ and scrolling tricks.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Post Reply