Skip to content
RetrogamingDeep Dive Published Updated 7 min readViews unavailable

MAME NVRAM Preservation: Separating Persistent Cabinet State from Save States

Preserve MAME arcade NVRAM by distinguishing it from save states, documenting initialization, controlling writes, and validating restored machine state.

Arcade machines can retain settings, bookkeeping, calibration, or player progress after power-off. In a MAME driver, that persistent state is not interchangeable with a save state. A save state captures a point-in-time emulation session so it can be resumed; NVRAM represents selected non-volatile hardware data that is read when the emulated machine starts and written through the NVRAM subsystem. Preserving one does not automatically preserve the other.

This distinction matters for research as well as convenience. A save state may include volatile CPU, device, video, and RAM state at an arbitrary frame. An NVRAM file may contain only bytes owned by a non-volatile device or share. It may be initialized from a driver-defined default when no prior file exists. The files can therefore answer different questions: “What did the whole machine look like at this moment?” versus “What cabinet data survives a normal restart?”

Follow the device’s declared storage

MAME provides an NVRAM device interface for non-volatile storage. A driver configures an NVRAM device and connects it to backing data, often through a named memory share. The device can use a default memory region, a zero-filled default, an all-ones default, a custom default callback, or a deliberately untouched initial buffer depending on the machine’s implementation. The source code also validates relevant sizes and reads the configured number of bytes; this is not a universal archive format with automatic schema migration.

A representative map and NVRAM setup has this shape:

void example_state::main_map(address_map &map)
{
    map(0x8000, 0x87ff).ram().share("nvram");
}

void example_state::machine_start()
{
    // Other driver initialization belongs here.
}

void example_state::example(machine_config &config)
{
    // CPU and other machine configuration omitted.
    NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
}

This fragment illustrates the relationship, not a complete compilable driver. Real code must use the correct map, tags, lifecycle and default policy for the board. A matching share name is significant: the NVRAM device resolves its backing storage in the owning device context. Do not add an NVRAM device to a driver merely because persistent behavior seems plausible. Establish the relevant chip or board behavior first, then model the persistence that software can observe.

The default policy is part of emulation behavior. Initializing to zero may be correct for one board and wrong for another. A memory region can provide factory or default contents. A custom callback may model a structured initial state. Leaving bytes untouched is distinct from filling them with a chosen value. If an initialization policy is changed, compare first boot, clean restart, and restored data instead of judging only a single attract-mode run.

Understand MAME’s file lifecycle

The -nvram_directory option selects where MAME stores NVRAM data; absent an override, the documented default is an nvram subdirectory of the current working directory. This is separate from configuration files and save-state files. Capture the actual command line and working directory in any preservation record, because launching the same build from another directory can make it appear that persistent data vanished when MAME is reading a different location.

MAME’s NVRAM documentation describes data being read at machine start and saved when the machine exits. The [no]nvram_save option controls saving on exit and is enabled by default. Disabling it keeps the previous on-disk contents instead of committing the in-memory changes from that run. It is useful for a controlled experiment, but it is not a general snapshot mechanism: if you need a known point-in-time artifact, use an explicit, documented procedure and verify the resulting files after a clean shutdown.

The backend’s .nv data should be treated as a driver-specific byte payload unless the driver documents more. MAME’s implementation reads a configured length into the backing memory and checks that the actual read length matches the expected length. The implementation itself notes limitations around width and endianness. Do not assume that a raw file is self-describing, portable to another emulator, safe to edit as text, or compatible across arbitrary revisions of a device model.

For a preservation capture, record at least:

  1. MAME release or source revision, system and software identifiers, and selected BIOS.
  2. The exact NVRAM directory and the file names, sizes, and cryptographic hashes after a clean exit.
  3. The driver’s current NVRAM backing model and default initialization behavior.
  4. The exact user-visible settings or cabinet state that the capture is expected to preserve.
  5. Whether the run began with an existing NVRAM file or with driver defaults.

Keep the original artifact immutable. Make a working copy for experiments, and never mix save-state files into the NVRAM evidence directory. A hash proves that a captured file has not changed relative to that hash; it does not establish which hardware state the bytes mean or whether the original driver model is accurate.

Controlled preservation and restore test

Use a disposable copy of the MAME data directory for a repeatable test. First move any existing NVRAM artifact out of the test path and record that it was absent. Start the system and record its default behavior. Change one known persistent setting through normal emulated controls, then exit MAME normally. Confirm that an NVRAM file was written in the directory selected by the command line, record its size and hash, and relaunch from the same environment. The setting should return if the driver models it as persistent.

Next, repeat with a copy of the captured file. Confirm that the restored behavior matches the expected setting, then compare the resulting file after a clean exit. Some machines update counters or clocks during the run, so a byte-for-byte unchanged file is not always the right expectation. Define the validation at the semantic level and document bytes that are expected to change. For a stronger test, conduct paired runs from identical copies and compare the outputs.

Do not validate persistence by loading a save state and then observing a setting. The save state may restore the running device state, while the NVRAM file is read at machine startup. Test those mechanisms separately: cold start with the NVRAM artifact, normal quit and restart, and save-state load. If their behavior differs, that may be correct and should be explained rather than hidden.

Avoid common data-loss traps

The most common mistake is confusing the current working directory with an explicit NVRAM directory. A second is using -nonvram_save during a session and assuming changes have been committed. A third is copying the artifact while MAME is still running; buffered or deferred writes can mean the copied file does not reflect the final session. Exit cleanly before archival and verify the file’s timestamp, length, and hash afterward.

Also avoid editing a file based only on observed byte offsets. The nvram_device may expose raw storage whose meaning is defined by driver code, and the same offset can represent a checksum, a counter, or a packed structure. If you must analyze bytes, preserve an untouched original and use a documented decoder tied to the exact driver revision. Do not import state from a different machine revision without checking size, format, and semantics.

ROM auditing and NVRAM preservation answer different questions. A ROM audit checks files against a driver’s expected metadata. NVRAM capture records mutable non-volatile state. Likewise, save-state compatibility is not the same as NVRAM compatibility. A state file can fail to load across machine changes even when the NVRAM payload still has a meaningful format, or a driver can change the NVRAM layout while its ROM set remains identical.

Provenance and responsible handling

Persistent arcade data can contain bookkeeping or other sensitive material in real cabinets. In a personal emulation workflow, preserve only data you are authorized to keep. For preservation research, document the acquisition context, avoid publishing personal or identifying data, and keep original dumps separate from normalized or decoded copies. A driver-defined default is evidence about the emulator’s model, not automatically proof of the original cabinet’s factory contents.

Good NVRAM work is reproducible: a documented launch path, an identified machine and driver revision, known initialization, clean shutdown, intact source artifact, and a restart test that demonstrates the intended persistence. These controls turn an opaque .nv file into a useful preservation artifact without claiming more than its bytes and driver model can support.

Related:

Sources:

Comments