retro-silicon

Components

common/save-state

Saves and loads a system's state by walking byte regions of its bus into a buffer

Portable Sim: passing (5 passed). Used by Nintendo Entertainment System. Source.

BoardStateRun
Sipeed Tang Nano 20Kverified2026-10-28, at ac84cec
Sipeed Tang Console 138Kverified2026-10-25, at f2536e6
TUL PYNQ-Z2verified2026-10-28, at ac84cec

Verified: the latest run on that board of a system using it passed every test, and the component hasn't changed since. Stale: it has changed since that run.

README

Saves a system’s whole state into a block-RAM buffer and loads it back, by walking a list of byte regions on the system’s own bus: the regions where the system maps its components’ save-state ports (docs/conventions.md) and its memories. A save taken on one board loads on any other board running the same system, at any clock.

Module save_state_ctrl.

Commands

Ports

PortDirWidthMeaning
clk, rstin1Clock; synchronous reset, which stops any walk and clears done
cmd, donein, out8Command and the last finished, as above
busyout1A command is running
hold, hold_frameout1Stop the system; at a frame boundary
readyin1The system has stopped as asked
b_req, b_we, b_addr, b_wdataout1, 1, 32, 8The bus: hold b_req until b_ack, as on the test shell’s bus; it drops for a clock between accesses
b_ack, b_rdatain1, 8
h_addr, h_we, h_wdatainAW, 1, 8The host’s access to the buffer, while not busy
h_rdataout8Registered: the byte at h_addr the clock before

Parameters

ParameterDefaultMeaning
NREG1Regions
BASES, LENS0Each region’s first address and length in bytes, region r in bits [r*32 +: 32]
AW15Buffer: 2^AW bytes, at least the regions’ total

Status

Sim tests, with two regions behind a bus of random latency and a stop that takes up to 20 clocks: a save fills the buffer with the regions in order, touching nothing else; a repeated command does nothing; a load after the system is scrambled restores every byte; nothing reaches the bus before ready; and a buffer the host wrote loads. Planted bug caught: a load that doesn’t wait for its buffer read.

In systems/nes, sim and both boards: a state saved mid-run and restored after a reset finishes with the uninterrupted run’s frames, trace CRC and cycle count, and a state saved at 27 MHz on SDRAM finishes the same at 50 MHz on block RAM.