Sega Saturn SMPC INTBACK: Peripheral Polling, Continuations, and VBlank Timing
Follow Saturn SMPC INTBACK requests from SH-2 parameters through peripheral scans, OREG chunks, continuation, timeout, and frame-aligned input delivery.
The Saturn’s System Management and Peripheral Control unit does more than return a controller bitfield. Its INTBACK command is a request/response protocol shared between SH-2 software and the SMPC. It can return system status, collect peripheral data, and deliver a variable-length result through output registers, with interrupt and continuation steps when the response is not complete. Treating a controller poll as an instantaneous host API call skips the command lifecycle and frame timing that Saturn software can observe.
Sega’s SMPC User’s Manual describes reset and clock management, peripheral control, port formats, and INTBACK command use. The programmer’s guide adds scheduling guidance for games that want input data aligned to a display frame. Those original documents are unusually valuable here: peripheral data acquisition is not just a controller protocol, but a timed system-management transaction.
SMPC control mode and direct mode
Saturn software can acquire peripheral state through SMPC control mode or use SH-2 direct mode for a port. SMPC control mode asks the SMPC to interpret the peripheral protocol and return a typed, structured result. Direct mode exposes a lower-level interface path to software. These are different ownership models; do not let an emulator’s convenient host controller abstraction erase the mode selected for a port.
In control mode, command parameters select whether status is returned, whether peripheral data is enabled, how ports are handled, and the amount of data reserved for each port. The result may describe the port state, peripheral IDs, data sizes, and data records for devices or multitaps. It is not safe to parse the output as a fixed two-byte Saturn pad struct: a mouse, keyboard, analog controller, or multitap changes the record shape. Unknown or disconnected peripheral values also need a defined path.
The manual’s port-size settings include short and extended acquisition modes, as well as zero-byte mode used when a port is being accessed through the direct interface. If both access methods are used, the game must configure them coherently; asking INTBACK to acquire a port that is being used in direct mode can conflict with the port ownership. A robust implementation tracks the acquisition mode per port and validates the expected result layout from the command parameters.
INTBACK is a multi-step transaction
At a high level, SH-2 software writes the request parameters and issues INTBACK. The SMPC collects the requested system and/or peripheral information, places status and data into its result registers, and raises the SMPC interrupt. Software reads the available output-register data. If more peripheral records remain, SH-2 software issues a continuation request; a break request terminates the collection. Only when the result is exhausted or explicitly broken is the command lifecycle complete.
That sequence is important for variable-length data and multitaps. The host must not synthesize all records at command issue time and immediately make them visible. The SMPC has a finite output interface, and the command’s continuation handshake determines when later result data is requested. Record the active request, current result cursor, chunk boundaries, pending interrupt, and whether software has requested continue or break. The output registers are a window into a protocol, not a static memory block.
The command parameters are written to IREG0, IREG1, and IREG2. IREG0 has different meanings at initial issue and at continuation/break time; using the initial status-selection field during a continuation phase is a protocol error. IREG1 configures port modes and whether peripheral data is returned. The manual explicitly says IREG2 must be set to the required value for INTBACK. An implementation should model the validity of a parameter set and command phase, not just the command byte.
Make command state explicit: idle, initial-request accepted, status result ready, peripheral collection active, chunk ready, awaiting continue/break, complete, or timed out. These are conceptual states for diagnostics, not names of undocumented hardware registers. The actual machine-visible status and interrupt behavior must follow Sega’s interface specification. A trace should show the written parameters and the transition that made an output byte valid.
VBlank alignment and acquisition budget
Sega’s programmer guidance places peripheral acquisition within the frame schedule. The guide describes issuing an INTBACK request after the VBlank-In interval has begun and before VBlank-Out, with a documented minimum separation after VBlank-In, so collection can be coordinated with VBlank-Out. In the non-optimized path, the SMPC begins acquisition at the relevant VBlank-Out point. That arrangement aligns the input sample to a predictable place in the display cycle rather than sampling whenever the SH-2 happens to run a controller routine.
The optimized path measures how long the configured set of peripherals takes to collect. Later scans can begin closer to VBlank-In with a safety margin; if a timeout occurs, acquisition returns to the conservative schedule and optimization is repeated. Device type and the number of connected devices affect the time. A single controller and a six-player multitap are not equivalent workloads, and the game must not assume that an optimized completion time remains valid after the peripheral topology changes.
The manual also describes timeouts: data that is not acquired by the designated VBlank-In is not simply filled in later as though it belonged to that frame. Repeated timeouts can cause the device to be treated as disconnected. Therefore, an emulator should distinguish “no buttons pressed” from “the peripheral did not answer before the acquisition deadline.” Conflating timeout with an all-zero pad report hides compatibility problems and can make a title respond differently under frame drops.
Frame timing tests should model both 50 Hz and 60 Hz system configurations, the command issue point, peripheral scan duration, and interrupt delivery. Do not base the SMPC schedule on host wall-clock time. It needs to be reproducible under pause, rewind, frame advance, fast-forward, and save-state restoration.
Parsing result records defensively
The result path begins with status and port information and can contain one or more peripheral records. Each record includes identification/type information and a data-size description. A multitap result can represent multiple downstream ports. The parser must use returned IDs and lengths, not fixed offsets copied from a standard controller example. Unknown IDs, zero data, truncated chunks, and inconsistent port states should produce bounded diagnostic errors rather than indexing beyond the output-register window.
Keep raw OREG bytes alongside the decoded device objects. That allows a capture to be reinterpreted if a later source uncovers a device format nuance. Add provenance fields to logs: command parameters, SMPC status, OREG index, port number, identified device type, frame number, scan start/end, interrupt cycle, and continuation count. A decoded button name is useful to a game, but raw bytes are essential evidence when the parser or device table is wrong.
For production software, follow the Sega library contract unless intentionally implementing the controller protocol in direct mode. The programmer manual says its library does not itself process the meaning of every connected peripheral’s data; applications still need to inspect IDs, presence, and device-specific fields. Thus “SMPC returned bytes” does not mean the game has validated the controller or converted its analog axes.
A bounded protocol trace
This Python example validates a diagnostic timeline for one INTBACK acquisition. It does not define register bit encodings. Its purpose is to keep chunk reads within the output-register window and require a terminal phase, so tests cannot silently accept an unfinished request.
from dataclasses import dataclass
@dataclass(frozen=True)
class IntbackStep:
cycle: int
phase: str
oreg_start: int
oreg_count: int
def validate_intback_trace(steps, oreg_capacity=32):
previous = -1
terminal = False
allowed = {"issue", "status", "peripheral", "continue", "break", "complete", "timeout"}
for step in steps:
if step.phase not in allowed:
raise ValueError("unknown INTBACK diagnostic phase")
if step.cycle < previous:
raise ValueError("events must be cycle ordered")
if step.oreg_start < 0 or step.oreg_count < 0:
raise ValueError("OREG range must be nonnegative")
if step.oreg_start + step.oreg_count > oreg_capacity:
raise ValueError("result exceeds the OREG window")
if terminal:
raise ValueError("event after terminal state")
terminal = step.phase in {"break", "complete", "timeout"}
previous = step.cycle
if not terminal:
raise ValueError("trace ended before completion, break, or timeout")
A hardware-accurate test should compare each step against the Sega-defined register protocol, then use this kind of validator as an independent guard on trace completeness. State-machine assertions are particularly useful for detecting a missed continuation or a second command issued while the preceding transfer is still active.
Verification plan
Test system-status-only INTBACK separately from peripheral-only and combined requests. Verify the initial parameter values, command issue, SMPC interrupt, OREG availability, and terminal status. Then use a standard digital pad, analog device, keyboard or mouse, and multitap so the test corpus exercises variable-length records and multiple continuation steps. Include an unsupported and disconnected device and preserve the distinction between absence, unknown ID, timeout, and valid neutral input.
For timing, schedule the request at each boundary permitted by the guide, measure scan start and completion, and inject a device that returns near the timeout deadline. Vary the number and type of attached devices and confirm the optimized path reverts to conservative timing when the measured budget is exceeded. Confirm that reads on the wrong frame do not retroactively change the frame’s latched input.
Save and restore at four points: before issue, while a request is active, after one result chunk with a continuation pending, and after an interrupt is raised but before the SH-2 reads the result. The restored state should produce the same OREG contents, interrupt, remaining chunks, and frame assignment. Compare raw register traces with a real Saturn or known-good emulator when available; document which evidence source was used.
Acceptance criteria
A faithful SMPC model treats INTBACK as a timed, interrupt-driven transaction with parameter-dependent result shape, bounded output chunks, continue/break semantics, per-port mode, and timeout behavior. It samples peripherals at the documented frame boundary and preserves acquisition work across save states. The debugger can answer not only “which button is down?” but also “which SMPC command sampled it, on what frame, with what device record, and did the result finish before its deadline?”
Related:
- Dreamcast Maple Bus: Device Discovery, Packet Framing, and Peripheral State
- Sega Saturn SCU DMA: Transfer Levels, Indirect Tables, and Bus Boundaries
Sources: