All About Circuits

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.


Technical Article May 31, 2026 by Shashikiran Sampathkumar

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.

 

Examples of an eFuse both before (left) and after (programming).

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.

 

System view of an RTL controller for eFuse programming

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.

Learn More About