Skip to content

olo_ft_ram_sdp_scrub

Back to Entity List

Status Information

VHDL Source: olo_ft_ram_sdp_scrub

Description

This component implements an ECC-protected simple dual-port RAM with an opportunistic memory scrubber.

The user-facing interface mirrors olo_ft_ram_sdp (write port + read port + error injection) plus a scrubber-enable input and four scrubber-status outputs. ECC encoding/decoding is transparent; the scrubber additionally walks the address space autonomously and writes corrected codewords back when a single-bit error is detected, refreshing the memory before a second upset can accumulate into an uncorrectable double-bit error.

By default the scrubber is free-running. An optional internal pacer can instead limit it to one pass every ScrubPeriod_g seconds and flag Scrub_Overrun if a pass overruns its period; see olo_ft_private_scrubber - Scrub Pacing.

This entity is synchronous-only: there is no IsAsync_g generic and no Rd_Clk / Rd_Rst port. The scrubber observes both user ports on a single clock to pick idle cycles. If you need independent read/write clocks, use plain olo_ft_ram_sdp without scrubbing.

This is useful in radiation-hardened designs where single-event upsets (SEUs) can flip bits in memory cells.

For background on the SECDED scheme, the codeword layout, error injection semantics and the constraints that apply across the ft area, see Open Logic Fault-Tolerance Principles.

Generics

Name Type Default Description
Depth_g positive - Number of addresses the RAM has. Must be at least 2.
Width_g positive - Number of data bits stored per address (word-width). The internal RAM is wider to accommodate ECC parity bits.
RamRdLatency_g positive 1 Read latency of the wrapped RAM, excluding ECC pipeline stages. Higher values can help close timing on the RAM read path.
RamStyle_g string "auto" Controls the RAM implementation resource. Passed through to olo_base_ram_sdp.
RamBehavior_g string "RBW" Controls the RAM behavior.
"RBW": Read-before-write
"WBR": Write-before-read
EccPipeline_g natural 0 Number of pipeline register stages within the ECC decoder (range 0..2). Total read latency is RamRdLatency_g + EccPipeline_g cycles. See olo_ft_ram_sdp for details.
ScrubClkHz_g real - Frequency of Clk in Hz, used only to size the optional scrub pacer. Set it to the actual clock frequency; must be >= 1000.0 when the pacer is enabled (ScrubPeriod_g > 0.0), ignored when free-running. See olo_ft_private_scrubber - Scrub Pacing.
ScrubPeriod_g real 0.0 Pacer period in seconds: one scrub pass is started every ScrubPeriod_g seconds (1 ms granularity). 0.0 (default) keeps the scrubber free-running; any value > 0.0 enables the pacer.

Interfaces

Clock and Reset

Name In/Out Length Default Description
Clk in 1 - Clock
Rst in 1 - Reset (high-active, synchronous to Clk). Resets the scrubber FSM and the read-valid pipeline; apply a reset pulse after startup, since the scrubber's address counter does not self-initialize in simulation. The stored RAM contents are unaffected (block RAMs cannot be reset).

Write Port

Name In/Out Length Default Description
Wr_Addr in ceil(log2(Depth_g)) - Write address
Wr_Ena in 1 - Write enable
Wr_Data in Width_g - Write data

Read Port

Name In/Out Length Default Description
Rd_Addr in ceil(log2(Depth_g)) - Read address
Rd_Ena in 1 - Read enable. Rd_Valid pulses '1' exactly RamRdLatency_g+EccPipeline_g cycles after each cycle on which Rd_Ena = '1'. Note: holding Rd_Ena = '1' permanently leaves no idle cycles and starves the scrubber entirely (see Opportunistic Scrubbing); deassert it on cycles without an actual read.
Rd_Data out Width_g N/A Read data (corrected if a single-bit error was detected)
Rd_Valid out 1 N/A Read-data valid. Pulses '1' only for reads the user issued; cycles consumed by the scrubber's own reads are masked out (see Architecture).
Rd_EccSec out 1 N/A Single error corrected flag. Unmasked pass-through of the decoder's SEC flag: qualify it with Rd_Valid = '1'. On a scrubber-owned read return the flag still appears here but Rd_Valid is masked to '0'; scrubber events are reported separately on Scrub_EccSec.
Rd_EccDed out 1 N/A Double error detected flag. Unmasked pass-through of the decoder's DED flag: qualify it with Rd_Valid = '1' (it can also assert on scrubber read returns, where Rd_Valid = '0'). Read data is unreliable when the flag is set.

Error Injection (optional)

These ports drive the internal olo_ft_ecc_encode instance (via the wrapped olo_ft_ram_sdp). Leave them unconnected for normal operation; see Open Logic Fault-Tolerance Principles - Error Injection for the shared latched-strobe semantics.

Note on scrubber interaction. The encoder's injection latch is consumed by the next encoder write, which in the scrub variant may be a scrubber writeback rather than your intended write. Drive ErrInj_Valid together with Wr_Ena (immediate injection, bypasses the latch), or pause the scrubber with Scrub_Enable = '0' while preloading (see Pausing the Scrubber). See Error Injection for the flip-pattern semantics.

Name In/Out Length Default Description
ErrInj_BitFlip in eccCodewordWidth(Width_g) all 0 Codeword-wide flip pattern. Each '1' bit XORs the corresponding bit of the stored codeword on the next write. Popcount 1 = SEC-correctable, popcount 2 = DED-detectable.
ErrInj_Valid in 1 '0' Strobe that latches ErrInj_BitFlip into the encoder's pending-injection register. The latched pattern is applied to the next write. If ErrInj_Valid = '1' and Wr_Ena = '1' in the same cycle the pattern is applied directly without going through the latch.

Scrubber Control

Name In/Out Length Default Description
Scrub_Enable in 1 '1' External enable. '1' = the scrubber runs in idle cycles. '0' suspends it on the same cycle: no new operation is issued, an operation in flight is aborted, the pacer's overrun watchdog is disarmed, and the address counter is preserved so coverage resumes from the same address when this is reasserted. Use it to pin the scrubber down during ECC error-injection tests.

Scrubber Status

These outputs report the scrubber's own activity as clean, directly countable one-cycle pulses; no external qualifier is needed.

Name In/Out Length Default Description
Scrub_EccSec out 1 N/A Pulses '1' for one cycle when a scrubber-issued read observed a single-bit error (SEC); gated internally so user reads never appear here. The scrubber writes that address back in the next free write slot, unless a user write to that address (or Scrub_Enable = '0') aborts the operation, in which case the address is retried (see Opportunistic Scrubbing).
Scrub_EccDed out 1 N/A Pulses '1' for one cycle when a scrubber-issued read observed a double-bit error (DED). The scrubber does not write the cell back (the corrected value is unreliable).
Scrub_PassDone out 1 N/A Pulses '1' for one cycle when the scrubber's address counter rolls over from Depth_g-1 back to 0, marking a completed pass over the memory.
Scrub_Overrun out 1 N/A Pacer watchdog. Pulses '1' (and a simulation warning fires) when a new scrub period begins before the previous pass completed. Disarmed while Scrub_Enable = '0' and tied '0' when the pacer is disabled (ScrubPeriod_g = 0.0). See olo_ft_private_scrubber - Scrub Pacing.

Detailed Description

Architecture

olo_ft_ram_sdp_scrub architecture

This wrapper composes olo_ft_ram_sdp (the SECDED-protected simple dual-port RAM: encoder + RAM + decoder) and olo_ft_private_scrubber (the opportunistic scrubber FSM).

The wrapper places the olo_ft_private_scrubber in front of the wrapped olo_ft_ram_sdp. The scrubber owns the user/scrubber arbitration: the user write port (Wr_*) and read port (Rd_*) feed the scrubber's user write and read channels, and the scrubber returns muxed write and read RAM channels that map 1:1 onto the RAM's write and read ports, so the wrapper carries no mux logic of its own. ErrInj_* go directly to the wrapped RAM's encoder, bypassing the scrubber.

The decoder's Rd_Data / Rd_EccSec / Rd_EccDed are forwarded straight to the user, while the user-facing Rd_Valid is the scrubber's masked read valid (scrubber-owned read cycles removed). The arbitration, the registered read/decide/writeback sequence, the read-valid masking and the optional pacer all live in the scrubber core -- see olo_ft_private_scrubber for the details.

Opportunistic Scrubbing

The scrubber uses the two RAM ports independently: it issues its reads on cycles where the user read port is idle (Rd_Ena = '0') and issues a pending SEC writeback on cycles where the user write port is idle (Wr_Ena = '0'). Only a user write to the address currently being scrubbed aborts the scrub operation in flight (user data is authoritative). The scrubber therefore keeps making progress under partial traffic on either port; it is fully starved only while the user reads on literally every cycle, which blocks new scrub reads. Starvation never causes data corruption; planted or accumulated errors simply remain until the scrubber gets read slots again.

See olo_ft_private_scrubber for everything the scrubber owns: the FSM (states, abort behavior, read-valid masking), the user-always-wins arbitration, the SEC-only writeback policy, and the optional pacer.

Pausing the Scrubber

Scrub_Enable = '0' suspends the scrubber on the same cycle: no new operation is issued, an operation in flight is aborted without writing back, and the pacer's overrun watchdog is disarmed. The internal address counter is preserved, so the next Scrub_Enable = '1' resumes scrubbing from the same address. This is the deterministic way to keep the scrubber from interacting with an injection-test sequence:

Scrub_Enable <= '0';
wait until rising_edge(Clk);     -- FSM held in Idle_s
ErrInj_BitFlip <= some_pattern;  -- preload the encoder's injection latch
ErrInj_Valid   <= '1';
wait until rising_edge(Clk);
ErrInj_Valid   <= '0';
... wait / set up / verify ...
Wr_Ena  <= '1';                  -- the latched pattern lands on this write
Wr_Data <= test_value;
Wr_Addr <= test_addr;
wait until rising_edge(Clk);
Wr_Ena  <= '0';
... read back, check Rd_EccSec = '1' ...
Scrub_Enable <= '1';             -- resume background scrubbing

ECC Overhead, Error Injection and Status Flags

The ECC behavior is identical to the wrapped olo_ft_ram_sdp, because it is the same instance. See the corresponding sections in Open Logic Fault-Tolerance Principles:

Constraints

See Open Logic Fault-Tolerance Principles - Constraints That Apply Across the Area for the no-byte-enables and no-initialization constraints. In addition, the scrubbing wrapper is synchronous-only: the scrubber observes the user ports on a single clock, so there is no async read clock (no IsAsync_g). There is deliberately no scrub variant of the true-dual-port RAM; see olo_ft_private_scrubber for the rationale.