Part of Curriculum: CDC, RDC and Low-Power RTL (Module 10: Multi-Rail SoC Power Sequencing Controllers)
View Full Roadmap →
Level 7 Industry Challenge ★ Advanced #59 50 pts ✓ Solved

SoC Multi-Rail Power Sequencing Controller

Advanced RTL & Protocol Design · advanced-rtl, soc-controllers, systemverilog, asic, fpga

Design a deterministic hardware power-on and power-down sequencing controller with supply-good handshake monitoring and fault timeout protection.

Write a synthesizable Verilog module named top_module matching the ports below exactly.
📐 Circuit Schematic Diagram
pwr_reqvdd_io_okpll_lockedpwr_en_ioclk_enablesys_rst_n_out>clkrst_nSOC MULTI-RAIL POWERDIGITAL HARDWARE BLOCK
⚡ Timing & Synthesizability Constraints

Timing Contract: Clocked on posedge clk with active-low async rst_n. Timeout limit = 15 cycles per state. Stabilization delay after clock enable = 4 cycles.

RTL Constraints: No rail order violation (IO must precede Core on power-up; Core must drop before IO on power-down). Synthesizable Verilog-2001.

Objective: Implement a multi-rail SoC power sequencer FSM. On pwr_req = 1, sequence voltage regulator enables (IO -> Core), monitor analog power-good flags, wait for PLL lock, enable clock gating, and deassert system reset after stabilization. Detect rail failure timeouts and execute an orderly shutdown.

Prerequisites: SoC power management, PMIC power sequencing, power-good handshaking, FSM design, watchdog timers.
PortDirWidthDescription
clk, rst_ninput1Sequencer clock and active-low async reset
pwr_reqinput1Power-up request (1=ON, 0=OFF)
vdd_io_ok, vdd_core_okinput1, 1Power-good indicators from external PMIC / regulators
pll_lockedinput1Analog PLL frequency and phase lock status
pwr_en_io, pwr_en_coreoutput1, 1Regulator enable controls (IO rail first, then Core)
clk_enableoutput1Clock distribution tree enable gate
sys_rst_n_outoutput1Deasserted (1) when system is operational
seq_erroroutput1Latched high if any stage exceeds 15-cycle timeout
Expected Waveform (Golden Timing Contract)
💡 Need Guidance? Progressive Hints (3 Levels)
Hint 1: Conceptual Direction & Hardware Primitives
Use a synchronous state machine with distinct states for power-up sequencing and reverse power-down collapse.
Hint 2: Implementation Architecture & Approach
Include a 4-bit timer that increments each cycle in wait states and resets upon state transitions.
Hint 3: Edge Cases, Timing & Verilog Syntax
If the timer reaches 15 in any wait state, transition immediately to S_ERROR and deassert all enables.
🔒 Reveal Verified Reference RTL Solution (Click to expand)
⚠️ Self-Discovery Warning: Try solving and simulating first! Viewing the verified reference implementation will bypass the real debugging experience.
Verified Synthesizable RTL
module top_module (
  input  wire clk,
  input  wire rst_n,
  input  wire pwr_req,
  input  wire vdd_io_ok,
  input  wire vdd_core_ok,
  input  wire pll_locked,
  output reg  pwr_en_io,
  output reg  pwr_en_core,
  output reg  clk_enable,
  output reg  sys_rst_n_out,
  output reg  seq_error
);

  localparam S_IDLE        = 4'd0;
  localparam S_EN_IO       = 4'd1;
  localparam S_EN_CORE     = 4'd2;
  localparam S_WAIT_PLL    = 4'd3;
  localparam S_EN_CLK      = 4'd4;
  localparam S_ACTIVE      = 4'd5;
  localparam S_DOWN_RESET  = 4'd6;
  localparam S_DOWN_CLK    = 4'd7;
  localparam S_DOWN_CORE   = 4'd8;
  localparam S_DOWN_IO     = 4'd9;
  localparam S_ERROR       = 4'd10;

  reg [3:0] state, next_state;
  reg [3:0] timer;

  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state <= S_IDLE;
      timer <= 4'd0;
    end else begin
      state <= next_state;
      if (state != next_state) begin
        timer <= 4'd0;
      end else begin
        timer <= timer + 4'd1;
      end
    end
  end

  always @(*) begin
    next_state = state;
    case (state)
      S_IDLE: begin
        if (pwr_req) next_state = S_EN_IO;
      end

      S_EN_IO: begin
        if (!pwr_req) next_state = S_DOWN_IO;
        else if (vdd_io_ok) next_state = S_EN_CORE;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_EN_CORE: begin
        if (!pwr_req) next_state = S_DOWN_CORE;
        else if (vdd_core_ok) next_state = S_WAIT_PLL;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_WAIT_PLL: begin
        if (!pwr_req) next_state = S_DOWN_CORE;
        else if (pll_locked) next_state = S_EN_CLK;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_EN_CLK: begin
        if (!pwr_req) next_state = S_DOWN_CLK;
        else if (timer >= 4'd3) next_state = S_ACTIVE; // 4 stabilization cycles
      end

      S_ACTIVE: begin
        if (!pwr_req || !vdd_io_ok || !vdd_core_ok || !pll_locked) next_state = S_DOWN_RESET;
      end

      S_DOWN_RESET: next_state = S_DOWN_CLK;
      S_DOWN_CLK:   next_state = S_DOWN_CORE;
      S_DOWN_CORE:  next_state = S_DOWN_IO;
      S_DOWN_IO:    next_state = S_IDLE;

      S_ERROR: begin
        if (!pwr_req) next_state = S_IDLE;
      end

      default: next_state = S_IDLE;
    endcase
  end

  // Output registered decoding
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      pwr_en_io     <= 1'b0;
      pwr_en_core   <= 1'b0;
      clk_enable    <= 1'b0;
      sys_rst_n_out <= 1'b0;
      seq_error     <= 1'b0;
    end else begin
      case (next_state)
        S_IDLE: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_IO: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_CORE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_WAIT_PLL: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_CLK: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b0;
        end
        S_ACTIVE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b1;
        end
        S_DOWN_RESET: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_CLK: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_CORE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_IO: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_ERROR: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
          seq_error     <= 1'b1;
        end
      endcase
    end
  end

endmodule
Verilog-2001 / SV Saved
Font: |
// Click Run Tests (or press Ctrl+Enter) to compile your RTL and simulate against hidden testbenches.
Simulation Timing Diagram (VCD Waveform)
100%
No simulation waveform yet. Run tests to simulate and generate VCD traces.
No compilation run yet. Syntax warnings and elaboration messages will appear here.
No simulation output yet. Raw stdout from vvp will appear here.

RTL Problems / Level 7 · Advanced RTL & Protocol Design

What You Will Learn

By solving SoC Multi-Rail Power Sequencing Controller, you will acquire core industry skills:

  • Synthesizable hardware modeling in standard Verilog-2001 / SystemVerilog.
  • Correct handling of interface port contracts, edge-triggered clocks, and active-low/high resets.
  • Simulation waveform interpretation and debugging using timing diagrams (VCD traces).
  • Architectural avoidance of timing violations, glitching hazards, and synthesis warnings.

Problem Statement & Requirements

Design a deterministic hardware power-on and power-down sequencing controller with supply-good handshake monitoring and fault timeout protection.

Hardware design teams at leading semiconductor firms evaluate these exact port contracts, race-condition assertions, and corner cases during technical design reviews and ASIC engineer interviews.

Objective: Implement a multi-rail SoC power sequencer FSM. On pwr_req = 1, sequence voltage regulator enables (IO -> Core), monitor analog power-good flags, wait for PLL lock, enable clock gating, and deassert system reset after stabilization. Detect rail failure timeouts and execute an orderly shutdown.

Prerequisites: SoC power management, PMIC power sequencing, power-good handshaking, FSM design, watchdog timers.

Port List & Interface Timing

The hidden testbench instantiates top_module. Module port names and bit-widths must match the interface contract exactly:

PortDirWidthDescription
clk, rst_ninput1Sequencer clock and active-low async reset
pwr_reqinput1Power-up request (1=ON, 0=OFF)
vdd_io_ok, vdd_core_okinput1, 1Power-good indicators from external PMIC / regulators
pll_lockedinput1Analog PLL frequency and phase lock status
pwr_en_io, pwr_en_coreoutput1, 1Regulator enable controls (IO rail first, then Core)
clk_enableoutput1Clock distribution tree enable gate
sys_rst_n_outoutput1Deasserted (1) when system is operational
seq_erroroutput1Latched high if any stage exceeds 15-cycle timeout

Timing Constraints & Synthesizable RTL Rules

⚡ Synthesizable Implementation Guidelines

Timing Contract: Clocked on posedge clk with active-low async rst_n. Timeout limit = 15 cycles per state. Stabilization delay after clock enable = 4 cycles.

Synthesis Constraints: No rail order violation (IO must precede Core on power-up; Core must drop before IO on power-down). Synthesizable Verilog-2001.

Architectural Deep Dive & Implementation Walkthrough

Why Modern SoCs Require Strict Power Sequencing

Modern System-on-Chips contain distinct power domains: I/O pads (1.8V/3.3V), analog PLLs (1.2V), and digital logic cores (0.75V - 0.9V). Violating the turn-on order can cause forward-biasing of parasitic PN junctions, leading to destructive CMOS latch-up.

Typical SoC Power-Up Sequence

  1. I/O Power First: Turn on I/O rails so pads enter safe tri-state mode without driving floating voltages onto unpowered external interfaces.
  2. Core Power Second: Ramp the internal digital core voltage. Wait for external PMIC power_good assertion.
  3. Analog Lock: Enable analog PLLs and wait for lock status.
  4. Clock Distribution: Ungate internal clock trees, allowing flip-flops to stabilize under valid clock edges.
  5. Reset Release: Deassert synchronous reset cleanly aligned to clock edges.

Common RTL Designer Pitfalls

⚠️ Common Mistakes to Avoid

Deasserting reset before clocks stabilize, or shutting down I/O rails before the core logic has ceased activity.

Silicon & Hardware Engineering Notes

🛠️ ASIC vs FPGA Hardware Considerations

Silicon power sequencers are placed in an "Always-On" (AON) power domain powered by an auxiliary backup battery or low-dropout regulator (LDO).

Starter RTL Code

module top_module (
  input  wire clk,
  input  wire rst_n,
  input  wire pwr_req,
  input  wire vdd_io_ok,
  input  wire vdd_core_ok,
  input  wire pll_locked,
  output reg  pwr_en_io,
  output reg  pwr_en_core,
  output reg  clk_enable,
  output reg  sys_rst_n_out,
  output reg  seq_error
);

  // Implement the multi-rail power sequencer FSM:
  // 1. IDLE: Wait for pwr_req == 1.
  // 2. EN_IO: Assert pwr_en_io. Wait for vdd_io_ok.
  // 3. EN_CORE: Assert pwr_en_core. Wait for vdd_core_ok.

Verified Reference Solution

🔒 Reveal Verified Reference RTL Solution
module top_module (
  input  wire clk,
  input  wire rst_n,
  input  wire pwr_req,
  input  wire vdd_io_ok,
  input  wire vdd_core_ok,
  input  wire pll_locked,
  output reg  pwr_en_io,
  output reg  pwr_en_core,
  output reg  clk_enable,
  output reg  sys_rst_n_out,
  output reg  seq_error
);

  localparam S_IDLE        = 4'd0;
  localparam S_EN_IO       = 4'd1;
  localparam S_EN_CORE     = 4'd2;
  localparam S_WAIT_PLL    = 4'd3;
  localparam S_EN_CLK      = 4'd4;
  localparam S_ACTIVE      = 4'd5;
  localparam S_DOWN_RESET  = 4'd6;
  localparam S_DOWN_CLK    = 4'd7;
  localparam S_DOWN_CORE   = 4'd8;
  localparam S_DOWN_IO     = 4'd9;
  localparam S_ERROR       = 4'd10;

  reg [3:0] state, next_state;
  reg [3:0] timer;

  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state <= S_IDLE;
      timer <= 4'd0;
    end else begin
      state <= next_state;
      if (state != next_state) begin
        timer <= 4'd0;
      end else begin
        timer <= timer + 4'd1;
      end
    end
  end

  always @(*) begin
    next_state = state;
    case (state)
      S_IDLE: begin
        if (pwr_req) next_state = S_EN_IO;
      end

      S_EN_IO: begin
        if (!pwr_req) next_state = S_DOWN_IO;
        else if (vdd_io_ok) next_state = S_EN_CORE;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_EN_CORE: begin
        if (!pwr_req) next_state = S_DOWN_CORE;
        else if (vdd_core_ok) next_state = S_WAIT_PLL;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_WAIT_PLL: begin
        if (!pwr_req) next_state = S_DOWN_CORE;
        else if (pll_locked) next_state = S_EN_CLK;
        else if (timer >= 4'd15) next_state = S_ERROR;
      end

      S_EN_CLK: begin
        if (!pwr_req) next_state = S_DOWN_CLK;
        else if (timer >= 4'd3) next_state = S_ACTIVE; // 4 stabilization cycles
      end

      S_ACTIVE: begin
        if (!pwr_req || !vdd_io_ok || !vdd_core_ok || !pll_locked) next_state = S_DOWN_RESET;
      end

      S_DOWN_RESET: next_state = S_DOWN_CLK;
      S_DOWN_CLK:   next_state = S_DOWN_CORE;
      S_DOWN_CORE:  next_state = S_DOWN_IO;
      S_DOWN_IO:    next_state = S_IDLE;

      S_ERROR: begin
        if (!pwr_req) next_state = S_IDLE;
      end

      default: next_state = S_IDLE;
    endcase
  end

  // Output registered decoding
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      pwr_en_io     <= 1'b0;
      pwr_en_core   <= 1'b0;
      clk_enable    <= 1'b0;
      sys_rst_n_out <= 1'b0;
      seq_error     <= 1'b0;
    end else begin
      case (next_state)
        S_IDLE: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_IO: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_CORE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_WAIT_PLL: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_EN_CLK: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b0;
        end
        S_ACTIVE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b1;
        end
        S_DOWN_RESET: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b1;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_CLK: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b1;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_CORE: begin
          pwr_en_io     <= 1'b1;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_DOWN_IO: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
        end
        S_ERROR: begin
          pwr_en_io     <= 1'b0;
          pwr_en_core   <= 1'b0;
          clk_enable    <= 1'b0;
          sys_rst_n_out <= 1'b0;
          seq_error     <= 1'b1;
        end
      endcase
    end
  end

endmodule

Related RTL Problems in Level 7

  • Async-Assert / Sync-Deassert Reset — Assert reset the instant it goes active, but only release it once it has been clean for 2 clock edges — the standard reset architecture for any real design.
  • 3-Flop CDC Synchronizer — A deeper 3-stage synchronizer for signals that need extra MTBF margin beyond the standard 2-flop chain.
  • Synchronized Rising-Edge Detector — Safely synchronize an asynchronous level signal, then produce a clean single-cycle pulse the moment it rises in the local clock domain.

Frequently Asked Questions

What does SoC Multi-Rail Power Sequencing Controller require?

Design a deterministic hardware power-on and power-down sequencing controller with supply-good handshake monitoring and fault timeout protection. Implement it as Verilog module top_module matching the listed ports.

Is this design combinational or sequential?

Tags: advanced-rtl, soc-controllers, systemverilog, asic, fpga. If a clock signal is present in the port table, implement it as sequential logic; otherwise, use continuous assignments or combinational blocks.

How is my solution graded?

A hidden SystemVerilog testbench simulates your module in the cloud judge. You pass when all directed corner cases match the golden model and the VCD timing waveform matches the contract.

How does this challenge help with semiconductor interviews?

Technical interviewers at NVIDIA, Qualcomm, Apple, and Intel routinely ask candidates to code, debug, and explain the timing waveforms of SoC Multi-Rail Power Sequencing Controller to assess real-world synthesizability and race-condition awareness.