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.
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.