The Problem: Screen Tearing

If your Z80 code draws objects to the screen while the video hardware is actively reading and displaying that part of memory, you get a visual artifact called screen tearing (a horizontal break in the image).

The Solution: VSync (Vertical Synchronization) Vertical Synchronization, or VSync, is the process of waiting until the video beam has finished drawing the current frame and is resetting to the top of the screen (the Vertical Blanking Interval, or VBI). By drawing only during the VBI, you ensure the user never sees partially rendered frames.

Method 1: Polling the VSync Flag

The simplest method is to poll a status register provided by the video hardware (often via an I/O port) until a specific bit indicates the VBI has started.

The Process: We repeatedly read the status port and use BIT to check the status flag.

STATUS_PORT EQU 0BEH        ; Example status port address

WAIT_FOR_VSYNC:
    IN   A, (STATUS_PORT)   ; Read the status byte
    
    ; Example: Assume VSync flag is Bit 7 (0 = VSync active)
    BIT  7, A               ; Check if the VSync bit is set (1)
    JP   NZ, WAIT_FOR_VSYNC ; If NOT Zero (bit is 1), keep waiting
    
    ; VSync is now active. Draw the frame!
    RET

Method 2: VSync via Interrupt (The Cleaner Way)

The most elegant and efficient way to handle VSync is to use a Timer Interrupt or a dedicated VSync Interrupt.

The Process:

  1. Set the Z80 to a specific Interrupt Mode (e.g., IM 1 or IM 2).
  2. Enable interrupts (EI).
  3. The video hardware (or a timer counting VBI signals) triggers an interrupt at the start of every VBI.
  4. Your Interrupt Service Routine (ISR) is executed, handling the drawing or timing logic.

Advantage: This method is non-polling, meaning the CPU is free to run game logic or other tasks during the time it would otherwise spend waiting in a loop.

The Game Loop Structure with VSync

Every program that uses animation should be structured around VSync for consistent performance:

Loop Structure:

  1. Read Input (Check keyboard/joystick).
  2. Run Logic (Move objects, collision detection).
  3. WAIT_FOR_VSYNC (Wait for the VBI to begin).
  4. Draw Frame (Update the screen memory).
  5. Loop (Go back to Step 1).