Skinny on NES scrolling

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Skinny on NES scrolling

Post by koitsu » Fri Jun 01, 2012 3:37 am

So I took what must be my hundredth attempt at understanding this mess:

http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

But found that the wiki suffers from the exact same problem that Loopy's original document does: lack of definition of what each variable represents. The irony is in the fact that at the top of the Wiki it references that exact problem, but (from what I can see) does very little to address that problem.

I would like to see the following variables explained/defined:

d
A
B
C
D
E
F
G
H
X

I'm left with the impression that A through H are just letter placeholders for specific VRAM address bits, but without an explanation it's literally impossible to tell. I can't even begin to fathom what X is.

I'm not the only one who after 10+ years still finds this document completely and entirely indecipherable. :-)

I'd love if someone could really write this thing up into a coherent step-by-step (read: verbose) guide, since there are a multitude of games that (obviously) rely on this behaviour, so emulating it wrong results in hard-to-discern breakage (e.g. in some games but not others).

P.S. -- And yeah, I'm aware of this, which is much more helpful but at a different level: http://wiki.nesdev.com/w/index.php/PPU_scrolling

EDIT: After reading the 2nd URL (PPU_scrolling), it's a little more clear, but not entirely. It seems to me these two pages should probably be re-written and merged into one well-written page. Given my history with documentation I'd be happy to do this except I do not understand how it works, hence my post here. :-)

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

Post by tepples » Fri Jun 01, 2012 3:46 am

The "d" is loopy's; the "A-H" is mine. I added the following:
"In the following, d refers to the data written to the port, and A through H to individual bits of this value."

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Fri Jun 01, 2012 4:02 am

Thanks Tepples. Is that edit correct though?

http://wiki.nesdev.com/w/index.php?titl ... oldid=3595

It turns "X" into "H", but then within the PPU registers section of the document, "x" (note that it's lowercase, yet in the main part of the document something was referred to as "X" (capital)) is still labelled as "fine X scroll (3 bits)" even though I don't see any visual indication of something controlling 3 bits.

Yep, still confusing. Hehe :D

EDIT: Oh, I see. For the 1st $2005 write:

Code: Select all

t:........ ...HGFED = d:HGFED...
x                   = d:.....CBA
Okay, so that explains what "x" is, and its 3 bits. However, now "x" isn't used anywhere further below that.

I think the formatting of all of these variables could really be improved in some way, probably if the entire thing was turned into a table and then each variable (t, v, x, and d) were given their own columns, along with a description column, thus every row would indicate what was written and which of the 8-bits of d went into what. I'll edit a sandbox page and see how it looks.

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

Post by tepples » Fri Jun 01, 2012 4:21 am

koitsu wrote:It turns "X" into "H"
I chose this letter for two reasons: 1. "horizontal", and 2. we've already designated the letter to mean something that's copied.
within the PPU registers section of the document, "x" (note that it's lowercase, yet in the main part of the document something was referred to as "X" (capital)) is still labelled as "fine X scroll (3 bits)" even though I don't see any visual indication of something controlling 3 bits.
I changed that: x:CBA = d:.....CBA.
However, now "x" isn't used anywhere further below that.
Background scrolling in units smaller than one tile is accomplished through 8-bit-long shift registers: a parallel-to-serial input stage (2 bits wide, receiving data from pattern tables) and a serial-to-parallel output stage (4 bits wide, with 2 of the bits fed by the input stage and 2 fed by the attribute register). Fine X scroll is the select value of an 8-way mux on the output stage. The only thing that changes fine X scroll is the first write to $2005. When you write to $2005, the change to fine X scroll takes effect immediately, as of the next pixel. The rest of the write doesn't take effect until the end of the scanline.
I think the formatting of all of these variables could really be improved in some way, probably if the entire thing was turned into a table and then each variable (t, v, x, and d) were given their own columns
Perhaps the reason that wasn't done in the first place might have had something to do with the 80 column limitation of common PC displays at the time.
Last edited by tepples on Fri Jun 01, 2012 4:29 am, edited 4 times in total.

UncleSporky
Posts: 385
Joined: Sat Nov 17, 2007 8:44 pm

Post by UncleSporky » Fri Jun 01, 2012 4:26 am

The absolute easiest thing would be short example code. It really wouldn't have to be that long. There's a link to some of tokumaru's code but we don't get to see what's in each variable.

An example like, here is a game with a status bar at the top, the player has just started playing and has triggered the first pixel of horizontal movement. Timed code has gotten us to this point, here are several variables and exactly what they contain, and here is a routine showing how to scroll 1 pixel over.

I realize it's important to understand the underpinnings, but some people learn better this way.

EDIT: On further review, tokumaru's code and the rest of the links (Shiru's vertical scroll question) are already very educational, but again, literally showing values being written and when to write them can also be informative.

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Fri Jun 01, 2012 5:24 am

UncleSporky wrote:The absolute easiest thing would be short example code. It really wouldn't have to be that long. There's a link to some of tokumaru's code but we don't get to see what's in each variable.
Tepples and UncleSporky, please review (no URL is not a typo):

http://wiki.nesdev.com/w/index.php/User:Koitsu

I provided a table-ised version (which IMHO is easier to read, especially given the formatting I did on it), and an example showing what v/t/x bits get changed. I'm not sure if Wiki syntax allows it, but I could probably colour-code the individual bits from the opcode which gets "transferred" into the t variable are a certain colour thus easier to read when looking at the "Instructions" vs. "After" columns.

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

Post by tepples » Fri Jun 01, 2012 6:02 am

koitsu wrote:Tepples and UncleSporky, please review (no URL is not a typo):

http://wiki.nesdev.com/w/index.php/User:Koitsu
The common practice for making drafts in your userspace on a wiki running MediaWiki is to name it something like "User:Koitsu/The skinny on NES scrolling".
I'm not sure if Wiki syntax allows it, but I could probably colour-code the individual bits
<span style="background: #FC9">A</span>

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Fri Jun 01, 2012 6:30 am

Thanks Tepples -- updated. I also found a mistake in my bit values (I know how/when I made this mistake), so I fixed that up. Things should be colourful and easier to note what goes where, though admittedly not friendly to those who are colour-blind.

Bare minimum, I think the Examples section would be worthwhile keeping. Though the preceding table-ised version of the ASCII diagram took me a while to do, I'm fine with giving it up.

I would also strongly advise that someone make an Example for this insanity (taken from PPU Scrolling) because that's one I STILL do not get/understand.

EDIT: I've integrated the Examples section into the skinny page.

User avatar
tokumaru
Posts: 11907
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Fri Jun 01, 2012 7:13 am

koitsu wrote:I would also strongly advise that someone make an Example for this insanity (taken from PPU Scrolling) because that's one I STILL do not get/understand.
That is just the order in which you have to write to the registers (and how the bits you write are supposed to be arranged) to fully reset the scroll mid-screen, considering all the rules loopy has detailed in his document.

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Fri Jun 01, 2012 7:19 am

Loopys new doc makes it pretty plain to figure out, and makes it clearer because it's basically a "Temp" and "V" ($2007 write) pointer, and when it shows what rights do what in the "T" register, it takes all of 3 seconds to understand.

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Fri Jun 01, 2012 8:10 am

tokumaru wrote:
koitsu wrote:I would also strongly advise that someone make an Example for this insanity (taken from PPU Scrolling) because that's one I STILL do not get/understand.
That is just the order in which you have to write to the registers (and how the bits you write are supposed to be arranged) to fully reset the scroll mid-screen, considering all the rules loopy has detailed in his document.
What makes no sense to me is the "XXXX/1" vs. "XXXX/2" nomenclature used in that post, which is also in the PPU scrolling wiki. Specifically:

Code: Select all

2006/1 --vv NNVV
2005/2 VVVV Vvvv
2005/1 HHHH Hhhh
2006/2 VVVH HHHH

2006/1 ---- NN-- (nametable select)
2005/2 VV-- -vvv (upper two bits of coarse V scroll, all bits of fine V scroll)
2005/1 ---- -hhh (fine horizontal scrolling) (takes effect immediately)
2006/2 VVVH HHHH (lower three bits of coarse V scroll, all bits of coarse H scroll)
Why is this not 2006/1, 2005/1, 2005/2, 2006/2? The behaviour of the "2005/2" write seems to be that of the 1st $2005 write per Loopy's doc, so I don't know why it's called "2005/2".

Code: Select all

x
    Fine X scroll (3 bits) 

Code: Select all

$2005 second write:

t:......HG FED..... = d:HGFED...
t:.CBA.... ........ = d:.....CBA

Code: Select all

$2005 first write:

t:........ ...HGFED = d:HGFED...
x:              CBA = d:.....CBA

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Fri Jun 01, 2012 8:17 am

koitsu wrote: Why is this not 2006/1, 2005/1, 2005/2, 2006/2?
$2005 and $2006 share the high/low byte latch for the 1st/2nd write.

User avatar
Bregalad
Posts: 7988
Joined: Fri Nov 12, 2004 2:49 pm
Location: Chexbres, VD, Switzerland

Post by Bregalad » Fri Jun 01, 2012 8:20 am

For me things became much, MUCH easier when I completely forgot about loopy's approach and went for my own approach.

Writing an address via $2006, simply, makes the adressed tile visible on the left of the next scanline.
The only tricky part is about the highest 4 bits - they are ignored (or you could say "hardwired to $2xxx", and instead the highest bits are used for fine Y scroll.
To adress fine X scroll you'll have to ressort to using $2005, as usual.

I think that's all there is to say about this topic.
Useless, lumbering half-wits don't scare us.

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Fri Jun 01, 2012 9:28 am

3gengames wrote:
koitsu wrote: Why is this not 2006/1, 2005/1, 2005/2, 2006/2?
$2005 and $2006 share the high/low byte latch for the 1st/2nd write.
Then can you verify that my example here is correct? http://wiki.nesdev.com/w/index.php/The_ ... 06_example

User avatar
tokumaru
Posts: 11907
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Fri Jun 01, 2012 12:28 pm

koitsu wrote:Then can you verify that my example here is correct? http://wiki.nesdev.com/w/index.php/The_ ... 06_example
Looks correct. I see no reason to write anything other than the NT index on the first write though, since everything else gets overwritten. Is your purpose to show that bits do get overwritten?

Post Reply