## Could anyone help me figure out the flaws of my scrolling logic?

**Moderator:** Moderators

### Could anyone help me figure out the flaws of my scrolling logic?

I'm trying to write the scrolling portion of my nes emulator without using the loopy v or t registers but i'm stuck working out the maths and i was wondering if i could use a bit of help. I store the horizontal scroll position in a value sx and the vertical scroll position in sy but for smb, since there is no vertical scroll ill consider it to be 0. Now when i'm calculating the nametable byte value i'll do (nametable address + (32 * (y / 8)) + ((x + sx)/ 8)) and if (x + sx) is greater than 256 then I'll subtract 256 from (x + sx) and invert the nametable address so 0x2000 to 0x2400 and vice versa. I can't see any flaws in the logic but smb does not work. It keeps flickering and when it scrolls, it scrolls from nametable 0 to 1 almost correctly but then halfway though nametable 1 it scrolls into nametable 0 instead of continuing through nametable 1 then 0 like it should. Any help please in working out the maths?

### Re: Could anyone help me figure out the flaws of my scrolling logic?

I don't see need to operate on values such as (x+sx). And honestly don't understand your formula.

I use next values:
(find article about scrolling here to understand idea behind 4 writes to this 2 registers)

You can drop Y from calculations, so last formula will be easier significally.

So just increase scroll_x in relatively low steps until overflow occurs - and then invert X bit in scroll_top. It will do seamless 512-pixels scrolling between nametables. Just keep it synchronized in pixel shifts with some global coordinate system by doing the same shifts every time.

I use next values:

Code: Select all

```
; We need 4 byte to be precalculated before IRQ interrupt:
scroll_top: .byte 0 ; Top (9-th) bits of X and Y shifted by 2 bits left (%0000YX00) - we'll write them in PPU_ADDR in 1st step
scroll_y: .byte 0 ; Lowest 8 bits of Y, - we'll write them in PPU_SCROLL in 2nd step
scroll_x: .byte 0 ; Lowest 8 bits of X, - we'll write them in PPU_SCROLL in 3rd step
scroll_bottom: .byte 0 ; In 4rd step we'll write in PPU_ADDR ((Y & $F8) << 2) | (X >> 3)
```

You can drop Y from calculations, so last formula will be easier significally.

So just increase scroll_x in relatively low steps until overflow occurs - and then invert X bit in scroll_top. It will do seamless 512-pixels scrolling between nametables. Just keep it synchronized in pixel shifts with some global coordinate system by doing the same shifts every time.

### Re: Could anyone help me figure out the flaws of my scrolling logic?

isn''t this the loopy v and t method but? The formula is from converting from pixel coordinates to nametable byte using array maths and i just replaced x with x + sx where sx is the horizontal offset in pixels

### Re: Could anyone help me figure out the flaws of my scrolling logic?

Not really... v and t is more about updating specific bits of the VRAM address, at the correct times. The thing is, you may be able to get some games working using a higher-level simplified scrolling logic, but lots of games do rely on how the actual hardware works.

The fact that t exists means that writes to $2005/$2006/$2000 don't immediately affect the effective scroll. A game can, for example, write a new X scroll value to $2005, and not do anything to commit that new value for several cycles.

I don't really know how SMB handles its scrolling, so I can't tell you exactly what's going wrong here, but there are no guarantees that a simplified higher-level implementation of the scroll logic will work with it. People often underestimate how complex SMB is to emulate, maybe because it's an older game, but it's known to rely on certain hardware quirks (e.g. palette mirroring, CHR-ROM reading) that often give new emulator authors trouble. And it does have a non-trivial mid-screen scroll change because of the status bar, so you might as well just implement the proper scroll logic instead of assuming specific games will work with an inaccurate implementation.