Skip to content

§ 3.1.4. ROM

Immutable read-only storage following the common cell/row/bank/device architecture. This is a digital mask-ROM-style model, not a writable EEPROM.

Component Description Structural Behavioral
ROMCell One fixed construction-time bit Yes Yes
ROMRow<C> C fixed bits in column order Yes Yes
ROMStorageBank<W> Rows plus one selected-row sensor per column Yes Yes
ROMAddressControl Decode address and chip/output enables Yes No
ROM<W> Complete asynchronous read-only device Yes Yes

Configuration

Width W, capacity N, and words-per-row K follow 3.1. image_hex contains consecutive bytes as pairs of hexadecimal digits, starting at byte address zero. No spaces or prefixes are accepted. The remaining capacity is initialized to zero; an odd-length, non-hex, or oversized image is rejected.

For example, image_hex="a53c81ff" gives four 8-bit words A5, 3C, 81, FF, two 16-bit words 3CA5, FF81, or one 32-bit word FF813CA5. This is little-endian byte packing. Device pins use word addresses, not byte addresses. Contents cannot be altered by reset, write commands, or a debug load after construction.

ROM uses the same component-reference pattern as FF and SRAM. The C++ examples describe binary pin behavior for validated construction parameters, including invalid addresses and disabled outputs, without simulator event scheduling. They are not registered simulator implementations. Compile in page order; tables contain every recorded checkpoint, with its number and time.

The cell's catalog parameter is value; a standalone row uses contents. Banks and devices use ROMDeviceConfig (depth_words, words_per_row, image_hex, record_history). The address controller accepts only geometry parameters; it has no image or history. Register names are memory.rom.cell, row, address-control, bank.W, and device.W under the memory.rom. prefix. Only the public bank/device wrappers are C++ width templates; row dimensions are runtime values.

3.1.4.1. ROMCell

One immutable construction-time bit.

IO pins

Pin Direction Width Description
Q Output 1 Fixed configured bit; no input pins

Behavior

The value parameter is 0 or 1 (default 0). It cannot be changed by an input, clock, reset, or debug load.

C++ example

Simplified binary behavior; simulation scheduling and four-state handling are described below.

struct ROMCellReference {
    const bool value;
    bool read() const { return value; }
};

Unknown inputs and timing

The output starts unresolved until the initial simulation event propagates, then is always the configured binary value. Both implementations schedule their first output even though there are no inputs.

Implementation

Structural implementation

A ConstantValue<1> child named MASK_BIT drives Q. This represents a fixed connection, not a flip-flop or a transistor-level mask-ROM cell.

Behavioral implementation

A terminal constant-output component publishes the configured value without the child.

The behavioral cell's visualizer shows Q as the programmed bit, using its recorded value. Selecting the structural implementation shows the fixed connection instead.

Examples

All 1 recorded rows of ROMCellTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (3f3be5125c460b70). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units QExpected output · 1 bit
#0fixed-one0 1

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The example constructs value=1 and checks Q. Zero-valued cells also occur in the row and bank examples.

Embedded simulation

The standalone ROMCellTest opens this component as MEMORY_ROOT. Use the explorer to compare structural and behavioral implementations.

Open ROMCell in the simulator

Source and tests

Test Coverage
ROMCellTest The complete standalone sequence shown above
MemoryDeviceContractTest Structural/behavioral agreement at settled checkpoints, including mixed hierarchy selection

3.1.4.2. ROMRow<C>

C fixed cells ordered by physical column.

IO pins

Pin Direction Width Description
Q_c Output 1 each Fixed value of column c, 0 ≤ c < C; no inputs

Behavior

The contents parameter contains 1–512 characters, each 0 or 1; default "0000". Characters are in increasing column order: "1010" means Q_0=1, Q_1=0, Q_2=1, Q_3=0, not an MSB-first integer. Selection belongs to the bank, not the row.

C++ example

Simplified binary behavior; simulation scheduling and four-state handling are described below.

#include <string>
#include <vector>
std::vector<bool> rom_row(const std::string& contents) {
    std::vector<bool> q;
    for (char bit : contents) q.push_back(bit == '1');
    return q; // The factory has already validated a nonempty binary string.
}

Unknown inputs and timing

Invalid characters, an empty row, or more than 512 columns are rejected at construction. Outputs settle from their initial events; valid ROM contents do not acquire X during reads.

Implementation

Structural implementation

Contains CELL_0 through CELL_(C−1), each a registered ROMCell. Cells are arranged left to right. A structural row may select behavioral cells.

Behavioral implementation

Retains the construction string and publishes each column directly, with the same startup and ordering contract.

Examples

All 1 recorded rows of ROMRowTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (3f3be5125c460b70). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units Q_0Expected output · 1 bit Q_1Expected output · 1 bit Q_2Expected output · 1 bit Q_3Expected output · 1 bit
#0fixed-row0 1 0 1 0

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The four-column example uses contents="1010" and checks every output in the initial settled checkpoint.

Embedded simulation

The standalone ROMRowTest opens this component as MEMORY_ROOT. Use the explorer to compare structural and behavioral implementations.

Open ROMRow<C> in the simulator

Source and tests

Test Coverage
ROMRowTest The complete standalone sequence shown above
MemoryDeviceContractTest Structural/behavioral agreement at settled checkpoints, including mixed hierarchy selection

3.1.4.3. ROMStorageBank<W>

Immutable rows with shared selected-row sensing.

IO pins

Pin Direction Width Description
WL_r Input 1 each Row selection, 0 ≤ r < N/K
COL_c Output 1 each Sensed bit, 0 ≤ c < W×K

Behavior

Exactly one binary wordline must be high. Each output then gives the corresponding column of that row. All-low, multi-row, or unknown selection returns X. The bank has no address decoding, output-enable, or write interface.

C++ example

Binary wordlines for any validated W/N/K geometry. The image is in byte-address order, with a zero-filled tail. Output columns use LSB-first order; empty optionals denote invalid row selection.

#include <vector>
#include <cstdint>
#include <optional>
std::vector<std::optional<bool>> rom_bank(unsigned width, unsigned slots,
    const std::vector<std::uint8_t>& image, const std::vector<bool>& wl) {
    std::vector<std::optional<bool>> columns(width * slots);
    unsigned count = 0;
    std::size_t row = 0;
    for (std::size_t r = 0; r < wl.size(); ++r) if (wl[r]) { ++count; row = r; }
    if (count != 1) return columns;
    for (std::size_t c = 0; c < columns.size(); ++c) {
        const auto byte = row * columns.size() / 8 + c / 8;
        columns[c] = byte < image.size() && ((image[byte] >> (c % 8)) & 1u);
    }
    return columns;
}

Unknown inputs and timing

An unknown wordline invalidates the entire selection; it is not treated as zero. Unselected cell values do not affect a valid selection. Scalar row/column interfaces limit standalone banks of either fidelity to 4,096 cells. The structural sensing path adds propagation delay.

Implementation

Structural implementation

ROW_r contains W×K fixed cells. Each COLUMN_c is a StaticReadColumn connected to column c of every row. Rows are stacked; sensing blocks align under their cells.

Behavioral implementation

Reads the fixed image bits directly after validating one-hot selection. It keeps the same expanded pins, geometry limits, and image interpretation.

Examples

All 3 recorded rows of ROMStorageBankTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (3f3be5125c460b70). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units WL_0Input · 1 bit WL_1Input · 1 bit COL_0Expected output · 1 bit COL_1Expected output · 1 bit COL_10Expected output · 1 bit COL_11Expected output · 1 bit COL_12Expected output · 1 bit COL_13Expected output · 1 bit COL_14Expected output · 1 bit COL_15Expected output · 1 bit COL_2Expected output · 1 bit COL_3Expected output · 1 bit COL_4Expected output · 1 bit COL_5Expected output · 1 bit COL_6Expected output · 1 bit COL_7Expected output · 1 bit COL_8Expected output · 1 bit COL_9Expected output · 1 bit
#0idle1 0 0 X not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked not checked
#1row-03 1 0 1 0 1 1 1 1 0 0 1 0 0 1 0 1 0 0
#2row-15 0 1 1 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The image is A5 3C 81 FF. The test first selects no row, then selects row zero and row one, checking all 16 sensed columns for each valid row.

Embedded simulation

The standalone ROMStorageBankTest opens this component as MEMORY_ROOT. Use the explorer to compare structural and behavioral implementations.

Open ROMStorageBank<W> in the simulator

Source and tests

Test Coverage
ROMStorageBankTest The complete standalone sequence shown above
MemoryDeviceContractTest Structural/behavioral agreement at settled checkpoints, including mixed hierarchy selection

3.1.4.4. ROMAddressControl

Address decomposition and active-low read qualification.

IO pins

Pin Direction Width Description
WORD_ADDR Input 32 Word address A
CE_N Input 1 Active-low chip enable
OE_N Input 1 Active-low output enable
ROW_ADDR Output 32 A/K for a valid address, otherwise X
COLUMN_ADDR Output 32 A%K for a valid address, otherwise X
ROW_ENABLE Output 1 CE_N=0 and valid address; independent of OE_N
OUTPUT_ENABLE Output 1 Qualified read, disabled output, or X

Behavior

For a binary address in [0,N), compute its row and word slot. Chip deselection disables the row. OE_N only controls publication: a valid selected row can remain active with its output disabled. A high CE_N or OE_N dominates other unknown inputs and releases the device output.

C++ example

Binary address/enables; nullopt represents an unknown output-enable or address.

#include <cstdint>
#include <optional>
struct ROMAddressReference {
    std::optional<std::uint32_t> row, slot;
    bool row_enable;
    std::optional<bool> output_enable;
};
ROMAddressReference rom_address(std::uint32_t a, unsigned n, unsigned k,
                                bool ce_n, bool oe_n) {
    const bool valid = a < n; // n and k are validated geometry.
    return {valid ? std::optional(a / k) : std::nullopt,
            valid ? std::optional(a % k) : std::nullopt,
            !ce_n && valid,
            ce_n || oe_n ? std::optional(false)
                        : valid ? std::optional(true) : std::nullopt};
}

Unknown inputs and timing

Unknown or out-of-range addresses never wrap. They produce X row/column addresses and a low ROW_ENABLE. OUTPUT_ENABLE is low if either enable is high, high only if both are low and the address is valid, otherwise X. This is a one-tick digital primitive.

Implementation

Structural implementation

A terminal combinational primitive computes selection and decomposes the address. It stores no image and has no clock. The row decoder and output buffer are separate components in the complete device.

Examples

All 7 recorded rows of ROMAddressControlTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (3f3be5125c460b70). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units CE_NInput · 1 bit OE_NInput · 1 bit WORD_ADDRInput · 32 bit COLUMN_ADDRExpected output · 32 bit OUTPUT_ENABLEExpected output · 1 bit ROW_ADDRExpected output · 32 bit ROW_ENABLEExpected output · 1 bit
#0disabled1 1 0 0x00000003 not checked 0 not checked 0
#1select-last-word3 0 0 0x00000003 0x00000001 1 0x00000001 1
#2invalid-address5 0 0 0x00000004 not checked X not checked 0
#3output-disabled-row-selected7 0 1 0x00000001 not checked 0 not checked 1
#4unknown-address-disabled9 0 1 0bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX not checked 0 not checked 0
#5unknown-enable11 0 X 0x00000001 not checked X not checked 1
#6chip-disable-dominates13 1 X 0x00000001 not checked 0 not checked 0

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The sequence checks chip deselection, the last word (A=3 → row 1, slot 1), and the first invalid address A=4. Additional cases exercise OE_N independently and unknown controls.

Embedded simulation

The standalone ROMAddressControlTest opens this component as MEMORY_ROOT. This component has one registered structural implementation.

Open ROMAddressControl in the simulator

Source and tests

Test Coverage
ROMAddressControlTest The complete standalone sequence shown above
MemoryDeviceContractTest Integration in the new structural devices and comparison with their compact implementations

3.1.4.5. ROM<W>

Complete asynchronous, word-addressed read-only device.

IO pins

Pin Direction Width Description
WORD_ADDR Input 32 Word index, 0…N−1
CE_N Input 1 Active-low chip enable
OE_N Input 1 Active-low output enable
READ_DATA Output W Selected immutable word, X, or Z

Behavior

No clock or command is required. With both enables low and a valid word address, publish the corresponding little-endian word. Either enable high releases the output. There are no write pins or reset operation.

C++ example

Binary read path for W=8/16/32, including little-endian byte assembly and the zero-filled image tail. The explicit result distinguishes valid data, high impedance, and an invalid address. Capacity is in words; image is in bytes and has already passed construction-time length/hex validation.

#include <cstdint>
#include <vector>
struct ROMReadReference {
    enum class State { Data, HighZ, Unknown } state;
    std::uint32_t data = 0;
};
template<unsigned W = 8>
ROMReadReference rom_read(const std::vector<std::uint8_t>& image, std::size_t words,
                          std::uint32_t address, bool ce_n, bool oe_n) {
    static_assert(W == 8 || W == 16 || W == 32);
    using S = ROMReadReference::State;
    if (ce_n || oe_n) return {S::HighZ};
    if (address >= words) return {S::Unknown};
    std::uint32_t data = 0;
    for (unsigned byte = 0; byte < W / 8; ++byte) {
        auto a = std::size_t(address) * (W / 8) + byte;
        if (a < image.size()) data |= std::uint32_t(image[a]) << (8 * byte);
    }
    return {S::Data, data};
}

Unknown inputs and timing

Enabled reads with an unknown address/control or an out-of-range address return X. A known disabled enable still returns Z. Read after the combinational paths settle; structural and compact propagation times differ. Image validation occurs before building the device.

Implementation

Structural implementation

ACCESS_CONTROL drives ROW_DECODE and output qualification. STORAGE contains fixed rows and their column sensors; COLUMN_SELECT chooses one W-bit slot; OUTPUT drives READ_DATA. There is no write distributor or erase block.

Behavioral implementation

Uses packed, zero-initialized MemoryStorage with the construction image prefix loaded once. The memory inspector is read-only; loadMemoryBytes rejects changes. This implementation supports large capacities without expanding cells. record_history=0 disables backing-store history, not wire history.

Examples

All 8 recorded rows of ROMTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (3f3be5125c460b70). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units CE_NInput · 1 bit OE_NInput · 1 bit WORD_ADDRInput · 32 bit READ_DATAExpected output · 8 bit
#0disabled11 1 0 0x00000000 0bZZZZZZZZ
#1word-019 0 0 0x00000000 0xA5
#2word-127 0 0 0x00000001 0x3C
#3word-236 0 0 0x00000002 0x81
#4word-343 0 0 0x00000003 0xFF
#5out-of-range53 0 0 0x00000004 0bXXXXXXXX
#6unknown-address54 0 0 0bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 0bXXXXXXXX
#7output-disabled57 0 1 0bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 0bZZZZZZZZ

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The example reads all four bytes of A5 3C 81 FF, checks out-of-range and unknown addresses, and disables the output. The displayed values and times come directly from the recorded test.

Embedded simulation

The standalone ROMTest opens this component as MEMORY_ROOT. Use the explorer to compare structural and behavioral implementations.

Open ROM<W> in the simulator

Source and tests

Test Coverage
ROMTest The complete standalone sequence shown above
MemoryDeviceContractTest W=8/16/32, K=1/2/4, image packing/zero tail, mixed fidelity, immutable debug interface, invalid configurations, and compact allocation
MemoryDeviceDocumentationTest Compile the exact references; test row conflicts, address/output controls, 8/16/32-bit image reads, little-endian packing, zero-filled tails and invalid addresses