Bricking Proof: Designing Safety-Critical RTL for eFuse Controllers
An RTL glitch in an eFuse controller can permanently brick costly silicon. This article covers defense-in-depth FSM design, redundant watchdogs, and formal SVA verification.
In the world of System-on-Chip (SoC) design, we are accustomed to the malleability of software and the resettable nature of registers. If we discover a bug, we write a patch. Electronic Fuses (eFuses), however, operate on a different principle: permanence.
eFuses are One-Time Programmable (OTP) elements used to store essential, immutable data. Examples include unique device IDs, cryptographic root keys, or post-silicon manufacturing trim values. Programming an eFuse is a physical, destructive event, as shown in Figure 1.

Figure 1. Examples of an eFuse both before (left) and after (programming). Image used courtesy of Rahman et al. by Creative Commons License 4.0
If your RTL controller has a glitch that triggers an accidental burn or applies the programming voltage for too long, you might permanently brick a $500 processor before it even leaves the factory.
This article provides a deep dive into designing robust, bricking-proof RTL for an eFuse controller, detailing essential safety mechanisms, Finite State Machine (FSM) construction, and critical pre-silicon verification strategies using SystemVerilog Assertions (SVA).
The Challenge: Bridging Digital Logic and Physical Permanence
An eFuse is fundamentally a high-stakes analog-digital interface. The digital controller must manage a precise sequence of events involving high-voltage (VDDQ) levels and specific timing windows ($T_{prog}$).
An eFuse is programmed by applying a high-current pulse that causes the material to migrate by a process called electromigration. This is the phenomenon where electric flow causes the conductor material to move. Programming permanently changes the fuse from a low-resistance (unblown) to a high-resistance (blown) state.
The RTL controller in Figure 2 must ensure this process is never accidental and always correct. Our focus is on Section 2 and Section 3 of that diagram: the State Machine (FSM) and Protection Logic.

Figure 2. System view of an RTL controller for eFuse programming. Image used courtesy of Shashikiran Sampathkumar
Robust RTL Design: Defense in Depth
To prevent accidental programming, we apply multiple layers of protection logic in our RTL design. These mechanisms ensure that a "burn" only occurs when intentionally commanded, properly sequenced, and mathematically validated.
Layer 1: The "Double-Knock" Unlock Sequence
The most critical protection is a requirement for a specific, multi-bit "Magic Key" unlock. A single bit-flip (due to noise or a cosmic ray) should never make the controller enter a programming state. The system must write a unique, deterministic pattern to a secure register before programming is enabled.
Layer 2: Hamming/Gray Coding for FSM States
If an FSM is encoded sequentially (00, 01, 10, 11), a single bit-flip can advance the state incorrectly (e.g., from IDLE directly to BURN). We use encoding with a higher Hamming distance (where multiple bits must change simultaneously) or Gray coding, combined with a default "Error" state to trap invalid transitions.
Layer 3: Redundant Hardware Timers (Watchdogs)
The programming pulse duration ($T_{prog}$) is critical. If $T_{prog}$ is too long, the fuse macro can overheat, damaging adjacent circuitry. The main timing counter must be supplemented by an independent, redundant hardware watchdog that forces the programming signal low if a maximum threshold is exceeded, regardless of the FSM’s state.
Implementing the FSM in SystemVerilog
We will implement a 6-state FSM that handles the safe lifecycle of a programming operation.
Sample SystemVerilog: The Fuse FSM
module efuse_ctrl_fsm (
input logic clk,
input logic rst_n,
input logic [31:0] magic_key_in, // APB/SPI input
input logic prog_cmd,
input logic timer_done,
output logic burn_en, // To fuse macro
output logic timer_start,
output logic [2:0] fsm_status
);
// ----------------------------
// Safety-Critical FSM Encoding
// (Hamming-distance-2 one-hot-like encoding)
// ----------------------------
typedef enum logic [2:0] {
IDLE = 3'b000,
UNLOCK = 3'b011,
SETUP = 3'b110,
BURN = 3'b101, // Critical programming state
VERIFY = 3'b111,
ERROR_SAFE = 3'b001
} efuse_state_e;
efuse_state_e state, next_state;
logic watchdog_kill;
// Unlock key (0xACE0FACE)
localparam logic [31:0] EFUSE_UNLOCK_KEY = 32'hACE0FACE;
// ----------------------------
// State Register
// ----------------------------
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else if (watchdog_kill)
state <= ERROR_SAFE; // Watchdog override
else
state <= next_state;
end
// ----------------------------
// Next-State & Output Logic
// ----------------------------
always_comb begin
next_state = state;
burn_en = 1'b0;
timer_start = 1'b0;
fsm_status = state;
case (state)
IDLE: begin
// Advance only on valid unlock key
if (magic_key_in == EFUSE_UNLOCK_KEY)
next_state = UNLOCK;
end
UNLOCK: begin
// Explicit program command required after unlock
if (prog_cmd)
next_state = SETUP;
end
SETUP: begin
timer_start = 1'b1; // Allow VDDQ to settle
if (timer_done)
next_state = BURN;
end
BURN: begin
burn_en = 1'b1; // Trigger analog burn
timer_start = 1'b1;
if (timer_done)
next_state = VERIFY;
end
VERIFY: begin
// Post-burn settling; return to IDLE when done
if (timer_done)
next_state = IDLE;
end
ERROR_SAFE: begin
// Trap state — requires full hardware reset to exit
next_state = ERROR_SAFE;
end
// Catch-all: any illegal encoding goes to safe state
default: next_state = ERROR_SAFE;
endcase
end
// ----------------------------
// Simplified Redundant Watchdog
// In production this is a separate counter module; watchdog_kill asserts
// if burn_en stays high longer than the permitted burn window.
// ----------------------------
endmodule
The code demonstrates the "Double-Knock" (requiring EFUSE_UNLOCK_KEY AND prog_cmd), Gray-adjacent FSM encoding, and the watchdog_kill override to the ERROR_SAFE state.
Verification Strategy: Testing the Un-Testable
Since we cannot simply reset a blown fuse, pre-silicon validation must be exceptionally rigorous.
The Behavioral Model of the Fuse Macro
A crucial part of the validation environment is a Verilog behavioral model of the fuse array itself. This model must maintain state (blown or unblown) between simulations and track cumulative programming time for each bit. It should flag an error if a bit is programmed twice or if the cumulative $T_{prog}$ exceeds specifications.
Dynamic Verification (UVM Sequences)
In a UVM environment, test sequences must move beyond standard register access. They must inject errors:
1. Glitched Input: Introduce single-cycle glitches on the prog_cmd or magic_key_in signals. The FSM must not leave IDLE.
2. Reset During Burn: Force a system reset while burn_en is high. The behavioral model must verify the fuse state is indeterminate but the controller logic reset safely.
Proving Safety With SystemVerilog Assertions (SVA)
Formal Verification using SystemVerilog Assertions is ideal for safety-critical logic, such as fuse controllers. Unlike dynamic testing, assertions can prove that a hazardous condition is mathematically impossible within the design constraints.
Here are two essential assertions that every fuse controller should implement.
SVA: Proving burn_en Requires Unlock
We must prove that the programming signal (burn_en) cannot go high unless the FSM has passed through the specific unlock state.
// Interface signal to detect when the unlock sequence was valid
logic unlock_sequence_complete;
assign unlock_sequence_complete = (state == UNLOCK) && (magic_key_in == EFUSE_UNLOCK_KEY);
// ASSERTION 1: No burn without prior unlock
// If burn_en is high, then unlock_sequence_complete MUST have been true
// at some point in the previous 'N' cycles.
property p_no_burn_without_unlock;
@(posedge clk) disable iff (!rst_n)
burn_en |-> $past(unlock_sequence_complete, 2); // Example delay for setup
endproperty
assert_no_unlocked_burn: assert property (p_no_burn_without_unlock)
else $error("CRITICAL SAFETY VIOLATION: burn_en asserted without prior valid unlock sequence!");
SVA: Proving T_prog Maximum Timing
We must also prove that the burn_en signal is never held high for longer than the maximum physical specification.
localparam T_PROG_MAX_CYCLES = 1000; // Example spec limit
// ASSERTION 2: Maximum programming duration limit
// Once burn_en is high, it MUST return low within T_PROG_MAX_CYCLES.
property p_burn_duration_limit;
@(posedge clk) disable iff (!rst_n)
$rose(burn_en) |-> strong(##[1:T_PROG_MAX_CYCLES] !burn_en);
endproperty
assert_burn_duration_limit: assert property (p_burn_duration_limit)
else $error("MAX TIMING VIOLATION: burn_en exceeded T_PROG_MAX_CYCLES! The fuse is bricked.");
Wrapping Up
eFuse design exemplifies the complexity and high stakes of integrating analog functionality within a digital SoC. We need to apply defense-in-depth principles in RTL. These include rigid unlock sequences, safe FSM encoding, and redundant watchdogs.
Following these guidelines, we transform an inherently risky process into a deterministic, secure operation. When combined with behavioral macro models and formal verification, we can be confident that the final silicon will be powerful, secure, and above all, brick-proof.