The Challenge of Scrolling

Creating the illusion of movement across a large background map (scrolling) is a major performance challenge for 8-bit CPUs. You must shift thousands of bytes of screen memory every single frame. Slow code will cause a noticeable flicker or lag.

The Solution: LDIR The Z80’s LDIR (Load, Increment, Repeat) instruction is the fastest tool for this job. It executes much faster than any software loop built with LD, INC, DEC, and JP.

Vertical Scrolling (Row by Row)

Vertical scrolling is the simplest because it involves moving entire rows of data.

Goal: Scroll the screen Up by one row (8 pixels). Every byte from row 1 to the end must move to the row above it.

The LDIR Setup (Scroll Up):

To scroll up, you must copy memory forward (from a low address to a high address). We set the source address to the row we want to keep, and the destination address to the row above it.

    LD   HL, ROW_2_START    ; Source: Start reading from row 2
    LD   DE, ROW_1_START    ; Destination: Write data to row 1
    LD   BC, SCREEN_SIZE_B  ; Total bytes to move (Screen size minus 1 row)
    LDIR                    ; High-speed copy
    
    ; The last row is now blank and ready for new map data.

Note on Direction: To scroll Down, you must use LDDR (Load, Decrement, Repeat) to copy the data backward (from a high address to a low address). This prevents the source data from being overwritten before it is read (the “memory overlap” problem).

Horizontal Scrolling (Pixel by Pixel)

Horizontal scrolling is far more complex because you can’t just move entire bytes. A one-pixel scroll requires shifting every bit in the entire screen buffer and then merging the result with new data.

The Method:

  1. Read a byte from screen memory.
  2. Use SLA (Shift Left Arithmetic) or SRA (Shift Right Arithmetic) to shift the 8-bit value left or right by one position.
  3. Write the resulting byte back to screen memory.
  4. Repeat this process for all ~6000 bytes.

Optimization: Use the Carry flag along with `RL′ (Rotate Left through Carry) to effectively shift a series of bytes, ensuring the bit that leaves byte N enters byte N+1. This is the only way to perform a fast, multi-byte shift.