Skip to content
RetrogamingDeep Dive Published Updated 7 min readViews unavailable

PC Engine VDC SATB DMA: Sprite Tables, VBlank Transfers, and Timing

Understand how the PC Engine HuC6270 stages sprite attributes in VRAM, copies them to internal SATB, and reports DMA completion to software.

The PC Engine’s HuC6270 Video Display Controller (VDC) uses an internal Sprite Attribute Table Buffer (SATB) to feed sprite evaluation. Software does not treat that table as ordinary CPU-visible RAM inside the VDC. Instead, the conventional workflow builds a sprite table in VRAM and asks the VDC to transfer it into its internal SATB. The transfer’s start time, repeat mode, completion status, and interaction with the raster all affect which sprite attributes are active for display.

This article focuses on that VRAM-to-SATB path and how it differs from the VDC’s separate VRAM-to-VRAM DMA. The Beetle PCE implementation provides an inspectable reference for register handling and scheduling; it is an emulator implementation, not a manufacturer’s hardware specification. The details below should be read alongside hardware-oriented references and tested against the target HuC6270 model when exact cycles matter.

VDC register access is indexed

The VDC is accessed through an index/status port and a data port. Software selects a VDC register, then reads or writes its 16-bit data through the data interface. The DMA-related registers include a control register, VRAM source and destination/count for VRAM-to-VRAM copying, and a source address for the SATB transfer. This indexed interface means a bug can result from a stale register selector as well as from the DMA’s own address calculation.

Maintain one explicit VDC register-selection state. A CPU write to the index port changes which register the next data-port operation targets; it does not itself copy any data. Low and high byte writes, where the CPU bus exposes them, must follow the VDC’s data-latch rules. Do not map each VDC register onto an unrelated host pointer and bypass the selector unless the CPU bus abstraction has already resolved the selected register.

The status register reports conditions including vertical blank, sprite collision/overflow, and completion of the two DMA types. Completion flags and their interrupt enables are distinct state. A transfer completing does not imply that software’s interrupt handler has run, and a completion flag can be polled even when interrupt delivery is disabled.

Two DMA engines, two different jobs

The VDC’s VRAM-to-VRAM DMA copies words within video RAM using source, destination, and length state. The SATB DMA is different: it reads the sprite attribute table from VRAM and transfers it to the VDC’s internal table. They have different register setup and completion status. Sharing a single generic memory-copy routine is sensible only if it preserves each transfer’s source/destination rules, event scheduling, and completion signaling.

The source register for SATB DMA identifies the VRAM location of the table image. Writing it requests a transfer for a future vertical synchronization point in common documented behavior. A control bit enables automatic repeated transfers at later vertical syncs. This permits double-buffering: the CPU or game logic prepares a new table in VRAM during a frame, while the VDC continues using its current internal copy until the scheduled exchange.

An important operational distinction is “request accepted” versus “copy visible.” Software can write the source address before the transfer occurs, but the on-screen sprite state should not be replaced immediately if hardware schedules the transfer for a later raster event. A renderer that copies SATB synchronously at register write time can show the next frame’s sprite positions too early.

Build a stable source table

Applications commonly prepare a complete set of sprite attributes in a designated VRAM area. Keep the table layout, stride, sprite count, and address range explicit in the game/emulator test. If two buffers are used, alternate them only after the prior transfer has completed or after the software’s chosen synchronization guarantees no reader still depends on the old one.

The staging idea can be expressed as:

frame_n:
    update sprite_table_next in VRAM
    write SATB source register = sprite_table_next
    wait for the documented vertical-sync transfer point
    observe SATB completion status
    make the completed buffer the next edit target

This is a workflow sketch, not a register-ready assembly routine. Correct source alignment, table size, and register write order come from the exact HuC6270 reference and the selected software library. The code should also avoid modifying the source words during the transfer window unless the hardware behavior for that race is known.

When diagnosing a missing or stale sprite, inspect the VRAM source bytes, selected source address, transfer pending/running state, VDC vertical phase, internal SATB snapshot, status flag, and interrupt enable. A screenshot alone cannot distinguish a bad table from a transfer that has not occurred yet.

Raster timing and CPU access windows

VDC DMA is part of the video controller’s timing, not a host-side bulk copy. The VDC has horizontal and vertical display/synchronization phases, and CPU accesses to video memory may have wait-state or access-window behavior. The emulator source models DMA progress against VDC cycles, observes active transfer state, and updates completion status when the scheduled work finishes. This is a useful clue for emulator architecture: advance the VDC and DMA on the same timeline as the CPU bus.

Do not assume every DMA operation is allowed during active display or that every transfer completes in one blanking period. The relevant mode and VDC phase matter. If software updates VRAM for tile data while SATB DMA is reading from the same VRAM area, the result depends on timing and bus ownership. Keep such overlapping accesses as explicit tests rather than letting host thread order decide which bytes are copied.

The sprite table’s relation to per-line sprite evaluation is separate from the DMA transfer. A completed SATB update changes the attribute source used by later VDC evaluation; per-scanline object limits and overflow signaling are another stage. This article does not treat DMA completion as permission to render every table entry on every line. The active renderer must still apply the VDC’s sprite fetch/evaluation rules.

Completion, IRQ, and repeat behavior

The VDC exposes separate completion status for SATB DMA and VRAM-to-VRAM DMA. Their interrupt enables are controlled independently through DMA control. A robust implementation sets the relevant completion flag when the transfer has finished and requests the VDC interrupt only if the corresponding enable is active. A guest write that clears or acknowledges status should follow the register’s documented semantics.

Automatic SATB transfer changes future behavior, not just current transfer. If enabled, the source table is reused at later sync points; if disabled, a one-time request should not silently repeat forever. Save states must preserve both the source address and whether repetition is armed. Restore should also preserve the next eligible vertical event, not merely copy the table into a host array.

When an interrupt-driven game appears to update one frame late, log the request write, next vertical-sync boundary, DMA duration, status flag, CPU interrupt mask, and handler entry. A late visible update can come from an incorrect transfer trigger, an incorrect completion interrupt, or software polling too late. These are different timing contracts.

Emulator validation plan

Use a deterministic test program that fills the VRAM table with easily recognizable coordinates/pattern indexes, configures a source, requests SATB DMA, and renders a frame before and after the expected transfer. Validate:

  1. The VDC register selector and data-port writes select the intended DMA source/control register.
  2. The internal SATB remains unchanged before the transfer event and changes after completion.
  3. Completion status is raised at the correct event, with interrupt delivery controlled independently by its enable.
  4. Auto-repeat behavior uses the programmed source on subsequent synchronization points; one-shot behavior does not.
  5. A VRAM-to-VRAM transfer does not accidentally set the SATB completion flag and vice versa.
  6. CPU writes to source VRAM near the active transfer boundary produce deterministic, documented results.
  7. A savestate during a pending transfer resumes the same number of VDC cycles and copies the same bytes.

Include native frame captures and internal SATB dumps. If you compare emulators, normalize frame crop and output aspect first, then inspect raw sprite attributes. A different aspect ratio cannot explain a stale SATB address, and an identical table does not prove that per-scanline evaluation is correct.

Engineering acceptance criteria

SATB DMA is modeled accurately when table staging, transfer request, event scheduling, internal-table update, completion flag, optional interrupt, and auto-repeat all have separate observable states. It should share the VDC event scheduler with the raster and CPU-access logic, and it should remain deterministic across save/load. Keep VRAM-to-VRAM DMA as a distinct operation with its own source/destination/length contract.

The PC Engine makes a general emulator design point clear: a video system may own an internal working copy that is not the same thing as the CPU’s source buffer. Respecting that boundary is essential for correct sprite timing, just as respecting a tile cache or scanline fetch buffer is essential on other consoles.

Related:

Sources:

Comments