Skip to content

olo_ft_ram_sp_scrub

Back to Entity List

Status Information

VHDL Source: olo_ft_ram_sp_scrub

Description

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

The user-facing interface is identical to olo_ft_ram_sp 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. Because the underlying RAM is single-port, the scrubber only issues a read or a writeback on cycles where the user is doing neither (WrEna = '0' and RdEna = '0'). User accesses are never stalled.

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 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_sp.
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_sp 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).

FT RAM Port

Name In/Out Length Default Description
Addr in ceil(log2(Depth_g)) - Address
WrEna in 1 - Write enable
WrData in Width_g - Write data
RdEna in 1 - Read enable. RdValid pulses '1' exactly RamRdLatency_g+EccPipeline_g cycles after each cycle on which RdEna = '1'. Note: holding RdEna = '1' permanently leaves no idle cycles and starves the scrubber entirely (see Opportunistic Scrubbing); deassert it on cycles without an actual read.
RdData out Width_g N/A Read data (corrected if a single-bit error was detected)
RdValid 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).
RdEccSec out 1 N/A Single error corrected flag. Unmasked pass-through of the decoder's SEC flag: qualify it with RdValid = '1'. On a scrubber-owned read return the flag still appears here but RdValid is masked to '0'; scrubber events are reported separately on Scrub_EccSec.
RdEccDed out 1 N/A Double error detected flag. Unmasked pass-through of the decoder's DED flag: qualify it with RdValid = '1' (it can also assert on scrubber read returns, where RdValid = '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_sp). 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 WrEna (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 WrEna = '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 idle port cycle, 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_sp_scrub architecture

This wrapper composes olo_ft_ram_sp (the SECDED-protected single-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_sp. The scrubber owns the user/scrubber arbitration: the single user port (Addr / WrEna / WrData / RdEna) feeds both of the scrubber's user channels. Because the underlying RAM is single-port, the scrubber is instantiated with SinglePortRam_g => true, so it collapses the muxed write/read addresses onto the one physical port itself and drives the wrapper's RAM address from its Ram_Addr output; this wrapper therefore carries no address mux of its own. ErrInj_* go directly to the wrapped RAM's encoder, bypassing the scrubber.

The decoder's RdData / RdEccSec / RdEccDed are forwarded straight to the user, while the user-facing RdValid 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

Because the underlying RAM is single-port, the scrubber issues a read or a writeback only on cycles where the user is doing neither (WrEna = '0' and RdEna = '0'); user accesses on other cycles do not disturb a scrub read already in flight, and only a user write to the address currently being scrubbed aborts the operation (user data is authoritative). The scrubber keeps making progress under partial traffic (any duty cycle that leaves idle port cycles); a user active on literally every cycle starves it, but starvation never causes data corruption.

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 ...
WrEna  <= '1';                   -- the latched pattern lands on this write
WrData <= test_value;
wait until rising_edge(Clk);
WrEna  <= '0';
... read back, check RdEccSec = '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_sp, 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 port on a single clock, so there is no async read clock. There is deliberately no scrub variant of the true-dual-port RAM; see olo_ft_private_scrubber for the rationale.