Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
    • Simulation for Sign-off
      • Gate-Level Simulation with a UVM Bench
      • Reset and X-Propagation Verification
      • Power-Aware Simulation with UPF
    • Safety, Acceleration and Models
    • Beyond Simulation
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Simulation for Sign-off
  1. Topics
  2. UVM Verification
  3. Verification in Industry Practice
  4. Simulation for Sign-off
  5. Power-Aware Simulation with UPF

Part 12 · Industry Practice · Intermediate

Power-Aware Simulation with UPF

Power domains, supplies, switches, isolation, retention and level shifters in IEEE 1801 UPF; what a power-aware simulator does; the power-control agent, sequences, checks and coverage of a power-aware UVM bench.

On this page

    A phone SoC passes every functional test. In the first power-management regression, the always-on interrupt controller starts reporting an interrupt from the DMA block while the DMA is switched off. Nobody wrote that bug into the RTL: the RTL has no idea power can be switched. The bug lives in the power intent, a separate file that said where isolation cells go and missed one output. How does a simulator know a block is off, and what does the testbench have to check while it is?

    The idea: power intent lives beside the RTL, not in it

    Low-power chips switch off blocks they are not using, keep some state alive while they are off, and run blocks at different voltages. None of that is written in RTL. It is described in a power intent file in UPF (the Unified Power Format, IEEE 1801), a Tcl-based format that every implementation and verification tool reads alongside the RTL. Think of the RTL as a building's floor plan and the UPF as its electrical plan: which rooms are on which circuit breaker, which rooms keep their lights on in a blackout, and which doors lock when a room goes dark.

    Concept

    What it is

    What goes wrong without it

    Power domain

    A group of instances sharing one primary supply that can be switched or scaled together

    Nothing to switch

    Supply set / supply net

    The power and ground nets that feed a domain, with their states (on, off)

    Simulator cannot tell a domain is off

    Power switch

    The header or footer that connects a domain to its supply under a control signal

    Domain can never turn off

    Isolation

    A clamp on a signal leaving an off domain, holding it at 0, 1 or its last value

    Floating or X values reach the always-on logic

    Retention

    Flops with a shadow element on an always-on supply: save before power off, restore after power on

    State lost; software must reprogram everything

    Level shifter

    A cell that translates a signal between two domains at different voltages

    Wrong logic levels or leakage between domains

    A power-aware simulator reads the UPF with the RTL (or the netlist) and adds this behaviour automatically. When a domain's supply goes off, it corrupts every flop and every output of that domain to X. When the isolation signal is active, it applies the clamp on the domain boundary. On the save signal it copies retained registers into their shadow, and on restore it copies them back. When the supply returns, non-retained flops stay X until reset. You change no RTL to get this; you add the UPF file and a power-aware option at compile time.

    Build it: a small UPF file

    The listing is illustrative: standard IEEE 1801 commands for a DMA domain that can switch off, with an isolation clamp on its outputs and retention on its configuration register. The syntax follows IEEE 1801-2013 and later (earlier UPF 2.0 used different option names for the isolation and retention supplies). A real file also declares supply ports and connects them to the chip's pads; check which UPF version your tools accept before copying any line.

    script.tcl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # Illustrative IEEE 1801 (UPF 2.1 or later) power intent for a switchable DMA
    create_supply_net VDD
    create_supply_net VDD_DMA
    create_supply_net VSS
    create_supply_set SS_AON -function {power VDD}     -function {ground VSS}
    create_supply_set SS_DMA -function {power VDD_DMA} -function {ground VSS}
    
    create_power_domain PD_TOP -include_scope -supply {primary SS_AON}
    create_power_domain PD_DMA -elements {u_dma}  -supply {primary SS_DMA}
    
    create_power_switch SW_DMA -domain PD_DMA \
      -input_supply_port  {in  VDD} \
      -output_supply_port {out VDD_DMA} \
      -control_port       {ctrl dma_pwr_en} \
      -on_state           {on_s in {ctrl}}
    
    set_isolation ISO_DMA -domain PD_DMA -applies_to outputs \
      -clamp_value 0 -isolation_signal dma_iso_en -isolation_sense high \
      -isolation_supply SS_AON -location parent
    
    set_retention RET_DMA -domain PD_DMA -elements {u_dma/cfg_q} \
      -retention_supply SS_AON \
      -save_signal {dma_save high} -restore_signal {dma_restore high}
    
    add_power_state PD_DMA.primary \
      -state {ON  -supply_expr {power == FULL_ON && ground == FULL_ON} -simstate NORMAL} \
      -state {OFF -supply_expr {power == OFF} -simstate CORRUPT}

    Read it top to bottom: two supplies, two domains (the top scope on the always-on supply, the DMA on its switched supply), a switch controlled by dma_pwr_en, an isolation strategy that clamps every DMA output to 0 while dma_iso_en is high, using cells placed in the parent and powered by the always-on supply, a retention strategy for one register, and the two power states of the DMA's supply. -simstate CORRUPT is what tells the simulator to corrupt the domain in the OFF state.

    The picture: the power-down and power-up sequence

    Sequence diagram: the power-control agent sets isolation, pulses save, switches the supply off (domain becomes X), switches it on, resets the domain, pulses restore and releases isolation.
    The order is the contract: isolate before switching off, save before switching off, reset and restore before releasing isolation. Most low-power bugs are one step out of order.

    Watch it run: what the simulator does, modelled by hand

    This course has no power-aware simulator, so the four-state model below writes out by hand the three things one would do from the UPF: corrupt the domain to X when the supply is off, clamp its output when isolation is on, and save and restore one register. It runs two power cycles: one correct, one with the isolation step missing. The always-on logic latches the interrupt with an OR, as a gate would.

    pd_dma.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    // not-run: needs a four-state simulator (run with Icarus)
    // What a power-aware simulator does to a switchable domain, written out by hand.
    // In a real flow none of this is in the RTL: the simulator applies it from the UPF.
    module pd_dma (                          // the switchable domain
      input  logic       clk, rst_n, pwr_on, save, restore,
      input  logic [7:0] cfg_in,
      input  logic       cfg_we,
      output logic [7:0] cfg_q,              // retained register
      output logic [3:0] cnt_q,              // ordinary register
      output logic       irq_raw
    );
      logic [7:0] cfg_ret;                   // retention shadow, on the always-on supply
      always_ff @(posedge clk or negedge rst_n or negedge pwr_on)
        if (!pwr_on)      begin cfg_q <= 'x; cnt_q <= 'x; end   // supply off: corrupt
        else if (!rst_n)  begin cfg_q <= '0; cnt_q <= '0; end
        else if (restore) cfg_q <= cfg_ret;
        else begin
          if (cfg_we) cfg_q <= cfg_in;
          cnt_q <= cnt_q + 4'd1;
        end
      always_ff @(posedge clk) if (save && pwr_on) cfg_ret <= cfg_q;
      assign irq_raw = pwr_on ? (cnt_q == 4'd15) : 1'bx;       // outputs of an off domain are X
    endmodule
    
    module top;
      logic clk = 0, rst_n = 0, pd_rst_n = 0, pwr_on = 1, save = 0, restore = 0, iso_en = 0, cfg_we = 0;
      logic [7:0] cfg_in = 0, cfg_q;
      logic [3:0] cnt_q;
      logic irq_raw, irq_iso, irq_seen;
      pd_dma u_dma (.rst_n(pd_rst_n), .*);           // the domain has its own reset
      assign irq_iso = iso_en ? 1'b0 : irq_raw;                 // isolation cell, clamp 0
      always_ff @(posedge clk or negedge rst_n)                 // always-on logic
        if (!rst_n) irq_seen <= 1'b0; else irq_seen <= irq_seen | irq_iso;
      always #5 clk = ~clk;
    
      task automatic show(string what);
        $display("%-26s pwr_on=%b iso_en=%b cfg_q=%h cnt_q=%h irq_iso=%b irq_seen=%b",
                 what, pwr_on, iso_en, cfg_q, cnt_q, irq_iso, irq_seen);
      endtask
    
      task automatic power_cycle(bit use_iso);
        @(negedge clk); if (use_iso) iso_en = 1;                show("isolate");
        @(negedge clk); save = 1; @(negedge clk); save = 0;     show("save");
        pwr_on = 0; @(negedge clk);                             show("power off");
        repeat (2) @(negedge clk);
        pwr_on = 1; pd_rst_n = 0; @(negedge clk); pd_rst_n = 1;  show("power on, domain reset");
        restore = 1; @(negedge clk); restore = 0;               show("restore");
        iso_en = 0; @(negedge clk);                             show("release isolation");
      endtask
    
      initial begin
        repeat (2) @(negedge clk); rst_n = 1; pd_rst_n = 1;
        cfg_in = 8'hC3; cfg_we = 1; @(negedge clk); cfg_we = 0;
        show("configured");
        $display("-- run 1: isolation and retention used correctly");
        power_cycle(1);
        $display("-- run 2: isolation missing");
        power_cycle(0);
        $finish;
      end
    endmodule
    Diagram
    configured                 pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=1 irq_iso=0 irq_seen=0
    -- run 1: isolation and retention used correctly
    isolate                    pwr_on=1 iso_en=1 cfg_q=c3 cnt_q=2 irq_iso=0 irq_seen=0
    save                       pwr_on=1 iso_en=1 cfg_q=c3 cnt_q=4 irq_iso=0 irq_seen=0
    power off                  pwr_on=0 iso_en=1 cfg_q=xx cnt_q=x irq_iso=0 irq_seen=0
    power on, domain reset     pwr_on=1 iso_en=1 cfg_q=00 cnt_q=0 irq_iso=0 irq_seen=0
    restore                    pwr_on=1 iso_en=1 cfg_q=c3 cnt_q=0 irq_iso=0 irq_seen=0
    release isolation          pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=1 irq_iso=0 irq_seen=0
    -- run 2: isolation missing
    isolate                    pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=2 irq_iso=0 irq_seen=0
    save                       pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=4 irq_iso=0 irq_seen=0
    power off                  pwr_on=0 iso_en=0 cfg_q=xx cnt_q=x irq_iso=x irq_seen=x
    power on, domain reset     pwr_on=1 iso_en=0 cfg_q=00 cnt_q=0 irq_iso=0 irq_seen=x
    restore                    pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=0 irq_iso=0 irq_seen=x
    release isolation          pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=1 irq_iso=0 irq_seen=x

    In run 1 the domain goes to X when off, the clamp holds irq_iso at 0, reset brings cnt_q back to 0, and restore brings cfg_q back to C3, the value saved before power off. In run 2 the X leaks through the missing clamp the moment the supply drops, and the always-on irq_seen flop captures it. Look at the last three lines: the DMA domain is back on and clean, but irq_seen stays X. An X that leaks into always-on state survives the power cycle that caused it, which is why missing isolation is a high-severity bug even when it seems to last only a few cycles.

    Power-aware UVM: what the bench adds

    A power-aware bench is the normal bench plus four pieces:

    • A power-control agent. If a power-management unit in the design drives the switch, isolation, save and restore signals, the agent is passive and monitors them. At block level, where nothing drives them, it is active and drives them from sequence items. Either way it publishes power-state transitions on an analysis port.

    • Power-state sequences. A virtual sequence that runs traffic, quiesces the block, runs the power-down steps in order, waits, powers up, and runs traffic again. Negative variants deliberately break the order (switch off before isolating, release isolation before restore) to prove the checks fire.

    • Checks. While a domain is off, every isolated output equals its clamp value. After restore, every retained register equals the value it had at save time (sample it at save through the monitor or a front-door read, compare after restore). After power-up, non-retained registers read their reset values. The scoreboard flushes the domain's expected traffic at power-off, exactly like the reset-aware scoreboard flushes on reset.

    • Coverage. Covergroups on the power-state transitions (ON to OFF, OFF to ON, and the illegal ones the design must refuse), crossed with what the block was doing when the request came (idle, mid-job, interrupt pending).

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // snippet: a power cycle as a sequence on the power-control agent's sequencer
    class dma_power_cycle_vseq extends uvm_sequence;
      `uvm_object_utils(dma_power_cycle_vseq)
      uvm_sequencer #(pwr_item) pwr_sqr;      // set by the test before start()
      rand int unsigned off_cycles;
      constraint c_off { off_cycles inside {[4:64]}; }
    
      function new(string name = "dma_power_cycle_vseq");
        super.new(name);
      endfunction
    
      task body();
        pwr_step(PWR_ISO,     1);             // 1. clamp outputs
        pwr_step(PWR_SAVE,    1);             // 2. save retained state (pulse)
        pwr_step(PWR_SWITCH,  0);             // 3. supply off: the simulator corrupts the domain
        pwr_step(PWR_IDLE,    0, off_cycles);  // stay off
        pwr_step(PWR_SWITCH,  1);             // 4. supply on
        pwr_step(PWR_RESET,   1);             // 5. reset non-retained state (pulse)
        pwr_step(PWR_RESTORE, 1);             // 6. restore retained state (pulse)
        pwr_step(PWR_ISO,     0);             // 7. release the clamp
      endtask
    
      // one item per control step; the driver holds each item's level for n clocks
      task pwr_step(pwr_ctl_e ctl, bit value, int unsigned n = 1);
        pwr_item it = pwr_item::type_id::create("it");
        start_item(it, -1, pwr_sqr);
        if (!it.randomize() with { kind == ctl; level == value; cycles == n; })
          `uvm_fatal("PWR", "randomize failed")
        finish_item(it, -1);
      endtask
    endclass

    The isolation check is the easiest to get wrong: compare the isolated output against its clamp while the domain is off, and sample the output on the always-on side of the isolation cell. A monitor sitting inside the switched domain sees X during off, which is correct and useless. In a real power-aware simulator the bench can also ask for supply states: IEEE 1801 defines a small SystemVerilog package for driving and querying supplies from a testbench, and each simulator adds its own power-aware debug commands. Check your tool's documentation for what it supports.

    What breaks: the first version of this demo

    The first version of the model above had a single reset shared by the domain and the always-on logic, so the power-up step had no domain reset. The run looked fine until the clamp was released:

    Diagram
    power on                   pwr_on=1 iso_en=1 cfg_q=xx cnt_q=x irq_iso=0 irq_seen=0
    restore                    pwr_on=1 iso_en=1 cfg_q=c3 cnt_q=x irq_iso=0 irq_seen=0
    release isolation          pwr_on=1 iso_en=0 cfg_q=c3 cnt_q=x irq_iso=x irq_seen=0

    The retained register came back (C3), but the ordinary counter cnt_q stayed X after power returned, and releasing isolation let that X out on irq_iso. It is the third classic low-power bug, next to missing isolation and a missing restore: non-retained state used before it is reset. Notice also that irq_seen stayed 0. In that first version the always-on flop was written if (irq_iso) irq_seen <= 1, and the if turned the X into the else branch, the X-optimism from the previous lesson, hiding the leak in RTL. The fixes were a separate domain reset pulsed at power-up, and an always-on capture written so that an X shows up instead of disappearing.

    Interview

    "How would you verify a block that can be power-gated?"

    A weak answer: "we run the tests with the UPF and check nothing breaks." It names no checks, no sequence, and no idea what "breaks" looks like.

    A strong answer walks the intent and the checks: "I start from the UPF: which outputs are isolated and to what value, which registers are retained, and the legal power states and sequence. The bench gets a power-control agent, passive if a PMU drives the controls, and virtual sequences that power-cycle at different points: idle, mid-transfer, interrupt pending. Checks: isolated outputs equal their clamp while off, retained registers match the saved values after restore, non-retained registers read reset values after power-up, nothing in the always-on logic goes X, and the scoreboard flushes the domain's in-flight traffic. Coverage of power-state transitions crossed with block activity tells me when I am done. Negative sequences break the order to prove the checks fire."

    Follow-ups: Why does the isolation cell need the always-on supply? (it must keep driving its clamp while the source domain is off) and What changes between power-aware RTL simulation and power-aware GLS? (in the netlist the isolation, retention and switch cells physically exist, so the simulation checks they were inserted and connected as the UPF says, not just modelled).

    Check yourself While the DMA domain is off, your scoreboard reports a stream of mismatches on its output port, all X. Is the design broken?

    Not necessarily. Outputs of an off domain are X by design; the question is whether they are isolated. Check the signal on the always-on side of the isolation cell: if it holds the clamp value, the design is fine and the scoreboard must stop expecting traffic (flush at power-off, as on reset). If the always-on side is also X, the isolation is missing or enabled too late.

    Check yourself After a power cycle, a retained configuration register reads back as its reset value instead of the value programmed before power-down. Name two likely causes.

    Restore happened before the domain reset, so the reset overwrote the restored value (the order must be reset, then restore); or save never captured the value, for example because it was pulsed after the supply had already dropped, or the register is not in the retention strategy's element list.

    Check yourself Why is a missing isolation clamp a serious bug even if the leaked X lasts only the few cycles before power returns?

    Because the X does not stay on the wire. Any always-on flop that samples it (an interrupt latch, a status bit, a state machine) captures an unknown value and keeps it after power returns, as irq_seen did in run 2. On silicon that becomes a random value: a spurious interrupt or a stuck state that depends on the power-up.

    Next: simulation is one way to get evidence. The Safety, Acceleration and Models topic covers what changes when the chip must be safe, when the simulation is too slow, and when the design includes analog.

    Previous

    240 / 280

    Next: Safety, Acceleration and Models

    Up next

    Up nextSafety, Acceleration and Models

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Gate-Level Simulation with a UVM Bench