(NOOB) good MMC chip explanations/tutorials?

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

lidnariq
Posts: 11430
Joined: Sun Apr 13, 2008 11:12 am

Re: (NOOB) good MMC chip explanations/tutorials?

Post by lidnariq »

puppydrum64 wrote: Tue May 25, 2021 5:40 pm You mean the bugged sprite overflow flag in $2002?
It's only buggy if there might be 8 sprites on one scanline. (It's the process of finding out if there would have been a 9th sprite that's buggy) If you guaranteeably have 7 or fewer sprites on a scanline it's fine. If you have 9 (or more) sprites suddenly on one scanline (and 7 or fewer on all previous scanlines), that'll reliably set it. So you can detect one Y coordinate that way.
puppydrum64 wrote: Tue May 25, 2021 5:40 pm Also how does the 2006-2005-2006-2005 thing work?
nesdevwiki:PPU scrolling § Split X/Y scroll
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: (NOOB) good MMC chip explanations/tutorials?

Post by tokumaru »

puppydrum64 wrote: Tue May 25, 2021 5:40 pmAlso how does the 2006-2005-2006-2005 thing work?
The PPU has a pair of registers it uses for scrolling: t (temporary VRAM address) and v (current VRAM address). These addresses have the following format:

Code: Select all

*yyyNNYY YYYXXXXX (15 bits)
yyy: fine Y scroll;
NN: name table;
YYYYY: coarse Y scroll;
XXXXX: coarse X scroll;
(the fine X scroll, xxx, is stored elsewhere)
Writes to $2005 and $2000.1/$2000.0 only modify t. At the beginning of the frame, the PPU copies t to v in order to draw the picture. At the end of each scanline, the PPU increments the vertical part of v and copies the horizontal part of t to v, effectively moving the scroll to the beginning of the next scanline.

Since the PPU copies the horizontal part of t each scanline, we can modify the horizontal part of t using $2005 and $2000.0 during rendering and those changes will be visible when a new scanline starts (except for the fine X scroll, which is updated immediately). The vertical part of t though, is only copied to v at the beginning of the frame, meaning that changes to the vertical scroll via $2005 and $2000.1 will only be visible on the next frame.

However, since the PPU also uses v to access VRAM, writing to $2006 also affects t, and after the second $2006 write, t is copied to v even during rendering! Unfortunately, since the video memory only goes up to $3FFF (14 bits), a double write to $2006 will only set 14 bits of t and v, and will CLEAR the top 2 bits, making it impossible to set the fine Y scroll to a value larger than 3 that way. Also, $2006 does not affect the fine X scroll at all, so $2006 alone cannot be used to fully set the scroll. But you can interleave $2006 and $2005 writes in order to set all the bits of the scroll, if you pay attention to the position of the bits.

The optimal way to set the scroll to any possible value is to write to these registers in the following order:

Code: Select all

$2006 (1st write): ****NN**
This updates the high byte of t. For this write you only need to bother with the name table bits, because all others will be overwritten on subsequent writes.

$2005 (2nd write): YY***yyy
Since $2005 and $2006 share the toggle that selects between 1st and 2nd writes, the PPU will see this as the second write to $2005, the one that sets the Y scroll. The bits marked with asterisks will be overwritten by a subsequent write.

$2005 (1st write): *****xxx
After the "second write" above, the toggle is now back in the "first write" position, so this sets the X scroll. The bits marked with asterisks will be overwritten by a subsequent write.

$2006 (2nd write): YYYXXXXX
This is the most annoying part of this trick, because this write overwrites portions of the coarse X and Y values, but it's absolutely necessary, because in addition to updating the low byte of t, this write triggers the copy of t to v. You need to shift a few bits around to put them in the correct positions, but after this write, you'll have successfully updated all 15 bits of v, along with the fine X scroll.
Currently, this is the only known way of updating all 15 bits of the scroll (along with 3 bits of fine X scroll) during rendering. If you don't need to modify all 15 bits, there may be shortcuts you can take, but a generalized routine to set the scroll to any arbitrary value will need to perform these 4 writes.
Post Reply