Embedded Systems · Safety-Critical Systems

Lockstep Cores and Comparator Logic in Safety Microcontrollers

How two cores executing the same instruction stream are compared cycle by cycle, what a comparator can and cannot detect, and why the delay between the lanes is a deliberate design parameter.

A lockstep processor runs the same program twice, on two cores in the same package, and compares the results. The claim it supports is that a fault affecting one core will be caught before its effect reaches an output. The claim is narrower than it sounds, and the narrowness comes from what “the same program twice” actually means in silicon: the two cores are not independent executions of a specification, they are two copies of the same logic fed the same inputs, which makes them excellent at catching physical defects and poor at catching design errors.

Two lanes, one instruction stream

The canonical arrangement has a master core and a checker core. Both receive the same instruction stream from the same fetch path, both decode it, both execute it, and both produce the same addresses, data values, and control signals. The checker’s outputs go nowhere except into a comparator. The master’s outputs drive the bus, the peripherals, and the memory system. The comparator, on every cycle, checks a defined set of signals for equality between the two lanes and raises an error when they differ.

The important structural detail is that the checker does not have its own program counter or its own instruction memory. It is not an independent processor that happens to run the same code; it is a second datapath slaved to the first. This is what makes the area cost acceptable, since the checker does not need instruction fetch, branch prediction, cache tag storage, or an interrupt controller of its own. It needs the execution units and enough pipeline state to produce comparable outputs. The area cost is a fraction of the core rather than a doubling, because the duplicated part is the logic that computes values and the shared part is everything that decides which values to compute.

Sharing the fetch path is also the mechanism’s main limitation. A fault in the shared instruction fetch, the shared bus, or the shared clock tree affects both lanes identically, produces identical outputs, and the comparator sees no discrepancy. Those shared structures are therefore excluded from the lockstep claim and must be covered by other mechanisms: parity or ECC on the instruction memory and caches, a bus with a check code, and a clock monitor. The comparator’s coverage is exactly the coverage of the logic that is duplicated, and the documentation for a lockstep device usually states which blocks are in the compared set and which are not.

What the comparator compares, and at which granularity

The set of compared signals is a design decision with a direct effect on both coverage and cost. At one extreme, the comparator watches the architectural outputs only: the address and data of each memory access, the register write-back value, and the exception taken. At the other, it watches internal pipeline signals cycle by cycle, including intermediate results, branch decisions, and control states.

Comparing architectural outputs catches any fault that changes the program’s observable behaviour, which is the property that matters, and it does so with less logic. Its weakness is latency: a fault inside a pipeline stage may not change an architectural result until several cycles later, and if the fault is transient, it may not change the result at all. Comparing internal signals catches the fault in the cycle it occurs, which shortens detection latency to a handful of cycles but requires a much wider comparator and constrains the two lanes to be cycle-identical in their internal timing.

Cycle-identical timing is why lockstep cores cannot simply be two ordinary cores with a synchronisation protocol. Any asymmetry in the pipeline, such as one lane stalling on a cache miss while the other does not, would produce a spurious mismatch. The design must guarantee that both lanes see the same stalls, which is achieved by having the checker’s memory accesses driven by the master’s results rather than performed independently. On some implementations the checker’s loads are replayed from a buffer filled by the master, so the checker never touches the cache and cannot diverge on a miss.

A mismatch raises an error signal that is routed to the fault collection unit, and the response is defined by the system rather than by the core: an immediate reset, a switch to a safe state, or an interrupt to a handler that performs an orderly shutdown. The comparator itself does not decide, and the decision must be made in a place that does not depend on the core that just failed.

The delay line and why lanes are offset

Some implementations run the checker a small number of cycles behind the master. The offset, usually a handful of cycles, exists to prevent a single transient from corrupting both lanes’ comparison inputs at the same instant and thereby cancelling itself out. If both lanes are at the same pipeline stage and a supply glitch flips the same bit in both, the comparator sees agreement and reports health. With a delay, the same glitch hits the master at one pipeline stage and the checker at a different one, so the resulting values differ and the comparator fires.

The delay has costs. The comparator must buffer the master’s outputs for the length of the offset, which is a pipeline of registers proportional to the offset in cycles. The offset also widens the window during which a fault in the master has already affected an output before the checker reaches the same instruction, so the error response must be fast enough that the output can be retracted or the actuator gated. A ten-cycle offset at 200 MHz is 50 nanoseconds, which is short compared with most actuator response times but not negligible against a gate that must clamp within a switching cycle.

The offset is a tuning parameter, not a free improvement. Too small and the common-mode rejection is weak; too large and the detection latency and buffer cost grow. Devices that expose the value in a register do so because the right setting depends on the expected fault durations in the application’s electrical environment.

Latent faults and the self-test requirement

A lockstep pair detects a fault only if the fault produces a difference. A fault that disables both lanes in the same way, or that is present in the checker’s comparator logic itself, produces silence. The mechanism that addresses this is the periodic self-test: at startup and at intervals during operation, the device injects a known fault into one lane and verifies that the comparator reports it.

The test is usually implemented in hardware, driven by a self-test controller that has access to the comparator’s inputs and to a set of test structures in each lane. It runs while the application is not executing safety functions, or it runs on a portion of the logic at a time, which is why the achievable diagnostic coverage is quoted together with the time needed to complete a full pass. A test that takes tens of milliseconds and runs every few hundred milliseconds is covering a small fraction of the logic at any moment, and the coverage figure must be interpreted against the fault detection time the safety concept assumes.

The latent fault problem is the reason lockstep alone is not a complete hardware argument. ISO 26262 introduces the distinction between single-point faults, residual faults, and latent faults precisely to force this analysis: a fault in a diagnostic mechanism is latent until the mechanism is needed, and if no other mechanism reveals it, the fault can accumulate undetected. A comparator is a diagnostic mechanism, so it needs its own coverage, and the self-test is what supplies it.

What a lockstep pair cannot catch

The failures the pair cannot see are systematic, and they are numerous enough to change the architecture.

A design error in the core’s logic affects both copies identically. A wrong branch condition, an erratum in the pipeline’s handling of a specific instruction sequence, a misprogrammed register that both lanes read the same way: none of these produce a mismatch. The same is true of a compiler bug, because both lanes execute the same binary. A lockstep pair therefore gives no coverage against software defects, and the software argument must come from process, review, and testing, which is the territory of DO-178C Objectives and Structural Coverage in the airborne world and its counterparts elsewhere.

Common-cause failures in the shared resources are the second gap. A single supply, a single clock, a single reset line, and a single package substrate are all shared, and a failure in any of them is seen identically by both lanes. A voltage droop that corrupts both cores at the same instant is a common-mode event, which is why the delay offset exists and why the supply is separately monitored. A die-level defect that affects an area used by both lanes has the same character, and device layouts separate the two lanes so that a single particle strike is unlikely to affect both identically.

The third gap is the comparator’s own decision. A comparator that fails to a state of “always agree” is undetectable by the comparison, which is why the self-test injects a mismatch rather than merely checking that the comparator is powered. This is a general property of checkers: a checker whose failure mode is silence requires a test that produces the condition it is supposed to detect.

Where the pair sits in the wider architecture

A lockstep core raises the integrity of a single channel; it does not make the channel redundant. A microcontroller with a lockstep core can still lose its supply, its sensor, or its actuator driver, and the failure of the whole package is a single-point failure for the function it implements. Systems that need higher hardware fault tolerance place two such microcontrollers in a redundant configuration and compare at the level of results rather than signals, which is the arrangement discussed in Voting Redundancy and Average Probability of Failure on Demand.

The choice between one lockstep pair and two independent channels is a choice about which failures are credible. A lockstep pair is cheaper, occupies less board area, and needs no agreement protocol, but its two lanes share everything outside the duplicated logic. Two independent channels share almost nothing but need a comparison mechanism, a synchronisation of their inputs, and a resolution when they disagree. Most automotive safety controllers take the first route for the processor and add monitoring for the supply and clock; most aviation systems with the highest integrity targets take the second, because the shared-resource argument for a single package is not one they can make.

The honest framing is that lockstep converts a class of random hardware faults from dangerous to detected, at the cost of area, a comparator that needs its own test, and an error response path that must work when the core that detects the error is itself suspect.

References

  1. ISO 26262-5:2018, Road Vehicles — Functional Safety — Part 5: Product Development at the Hardware Level — International Organization for Standardization
  2. IEC 61508-2:2010, Part 2: Requirements for Electrical/Electronic/Programmable Electronic Safety-Related Systems — International Electrotechnical Commission
  3. ARM Cortex-R5 Technical Reference Manual — Arm Limited