Detection catches the faults the designer predicted; redundancy catches the ones nobody predicted, the flipped flop in a control state machine, a double flip in different bytes of an SRAM word, the clock glitch that no checker modelled. But duplication doubles area and power on everything it touches, and a poorly placed checker flags correct behaviour as faulty. The task is choosing one pattern per structure and doing the cost arithmetic that justifies it.
Two patterns cover the extension, each matched to the structure it protects. Parity protects storage and transport: one parity bit per byte on the SRAM read path detects an odd number of flips in that byte at the receiver with single-cycle latency, and one bit per 32-bit word (33 wires) protects each stream bus. Lockstep duplicates small control logic with the same inputs and compares outputs, with a delay between the copies so that a fault striking both identically does not slip through: here the reset and power sequencers in nano_rstpwr are duplicated as one pair. Other structures get no extra pattern: the sequencer's own steps need none beyond the lockstep pair, and the DMA datapath and the fabric are not duplicated because that would double the largest blocks; they are covered by error responses and end-to-end checks. Parity has a residual risk the review must write down: two flips in the same byte cancel and go undetected, and the teaching design accepts that.
# not-run: NanoSoC safety extension, one pattern per structure, illustrative costs
sram0, sram1: parity per byte, 36-bit macros (one extra bit per byte = 12.5 percent)
stream buses: one parity bit per 32-bit word (33 wires), negligible area
reset and power logic: lockstep pair of nano_rstpwr sequencers, delayed compare (100 percent of 0.015 mm2)
fabric, DMA datapath: no duplication; error responses and end-to-end checks
residual risk: two flips in the same byte are not detected by per-byte parity# Cost audit: one pattern per structure, cost derived from the area budget.
SRAM_MM2, RSTPWR_MM2, BLOCK_SUBTOTAL_MM2 = 0.100, 0.015, 0.585 # NanoSoC budget
STRUCTURES = [ # (structure, pattern, protected area mm2, area fraction added)
("sram0", "parity", SRAM_MM2, 0.125),
("sram1", "parity", SRAM_MM2, 0.125),
("stream_buses", "parity", 0.0, 0.0), # 33 wires, negligible area
("rstpwr_sequencers", "lockstep", RSTPWR_MM2, 1.0),
]
def audit(structs):
problems = []
names = [s[0] for s in structs]
problems += ["two patterns: " + n for n in set(names) if names.count(n) > 1]
problems += ["unknown pattern: " + s[0] for s in structs
if s[1] not in ("parity", "lockstep")]
return problems
assert audit(STRUCTURES) == []
overhead = sum(a * f for _n, _p, a, f in STRUCTURES)
assert abs(overhead - 0.040) < 0.0001, overhead
assert overhead / BLOCK_SUBTOTAL_MM2 < 0.07 # 6.8 percent
# the old contradiction (sequencer both lockstep and temporal) is now rejected
assert audit(STRUCTURES + [("rstpwr_sequencers", "temporal", 0.015, 0.05)]) != []
print(f"PASS: 4 structures, one pattern each; overhead {overhead:.3f} mm2 = {overhead / BLOCK_SUBTOTAL_MM2:.1%} of block area")The pattern choice per structure with the fault class it catches, the residual risk it leaves and the cost beside it, matching the table above in text and in code.
The comparator and parity outputs routed to the fault controller as held levels, not to log files or LEDs.
The common-cause argument for each lockstep pair: delay, diversity or independence stated, not assumed.
Every fault flag that leaves PD_SW into the always-on fault controller clamped, counted on top of the 114 isolation cells.
Inject the faults redundancy should catch: flip one bit in a protected SRAM word and confirm the parity flag, force one lockstep copy to disagree and confirm the compare fires, and flip two bits in different bytes of one word to confirm both parity bits fire. Each injection must end at the fault controller input from the previous lesson; redundancy that flags locally but never reports is the silence the whole topic refuses.
A common-cause fault that struck both copies identically: same glitch, same bad input, same misconfigured mode. The delay between copies and input diversity exist exactly to defeat this, which is why the review demands the common-cause argument per pair.