Skip to main content

Example Walkthrough: Power Intent for the PWM Register Block

Every construct across this topic's three sections now exists on its own page. This capstone applies all of it to one real example: the PWM register block already built in UVM's RAL section — CTRL, PERIOD, DUTY, and STATUS registers, addressed at 0x00–0x0C — giving it a genuine power domain, a switch, isolation, and a retention strategy on the state actually worth preserving.

Why this DUT, and what's actually worth power-gating on it​

The PWM's register model already describes exactly the state a retention strategy would preserve — CTRL, PERIOD, and DUTY hold configuration a real system would rather not lose every time this block powers down, especially if it power-gates frequently to save energy between PWM-active periods. STATUS.running is read-only and reconstructed from live hardware state, not something retention needs to touch.

The power domain and its supplies​

set_scope u_pwm
create_power_domain PD_pwm -include_scope

create_supply_port VDD_pwm -direction in
create_supply_net VDD_pwm_net
connect_supply_net VDD_pwm_net -ports VDD_pwm
create_supply_set pwm_primary -function {power VDD_pwm_net} -function {ground VSS_net}

create_supply_port VDD_pwm_ret -direction in
create_supply_net VDD_pwm_ret_net
connect_supply_net VDD_pwm_ret_net -ports VDD_pwm_ret
create_supply_set pwm_retention -function {power VDD_pwm_ret_net} -function {ground VSS_net}

associate_supply_set pwm_primary -handle primary
associate_supply_set pwm_retention -handle default_retention

Two supply sets, two different jobs: pwm_primary is what the domain runs on during normal operation; pwm_retention is a smaller, always-available supply that stays up through a power-down specifically so the retention strategy below has somewhere to hold state.

The power switch​

create_power_switch sw_pwm \
-domain PD_pwm \
-input_supply_port {VDD_always_on VDD_always_on_net} \
-output_supply_port {VDD_pwm VDD_pwm_net} \
-control_port {EN pwm_pwr_en} \
-on_state {on_state VDD_always_on EN} \
-off_state {off_state {!EN}}

pwm_pwr_en is the real signal a system-level power controller would drive to actually gate this domain's power — the same EN role Power Switches and The Power-Up Sequence already worked through.

Isolation on the bus-facing outputs​

set_isolation pwm_iso -domain PD_pwm -applies_to outputs -clamp_value 0
set_isolation_control pwm_iso -domain PD_pwm \
-isolation_signal pwm_iso_en -isolation_sense high -location parent

Every signal PD_pwm drives outward — rdata, STATUS.running — gets clamped to 0 while pwm_iso_en is asserted, rather than exposing whatever undefined value the domain's real logic holds while unpowered.

Retention on the configuration state​

set_retention pwm_ret -domain PD_pwm -retention_supply_set PD_pwm.default_retention
set_retention_control pwm_ret -domain PD_pwm \
-save_signal {pwm_ret_save high} \
-restore_signal {pwm_ret_restore high}
map_retention_cell pwm_ret -domain PD_pwm -lib_cell_type DRFF

Applied to CTRL, PERIOD, and DUTY specifically — not STATUS, which has nothing worth retaining — this is the selective application Retention Strategies named directly: retention costs real area on every flop it touches, spent here only on the state a system restart would otherwise have to reconfigure by hand.

Why no level shifter appears in this example​

This walkthrough covers switching, isolation, and retention, but deliberately shows no set_level_shifter at all — worth explaining rather than leaving as a silent gap, since Level Shifter Strategies is a real strategy this topic covers in equal depth to the other three. Level shifting and isolation solve genuinely independent problems: isolation exists because PD_pwm can be powered off entirely, leaving its outputs undefined; level shifting exists only when two simultaneously-powered domains run at genuinely different voltages. pwm_primary and the always-on domain feeding sw_pwm here are assumed to run at the same supply voltage, so signals crossing that boundary need clamping while powered down (isolation, already shown above) but never voltage translation while both sides are up — there's no voltage gap for a level shifter to bridge. A real SoC integrating this PWM block into a genuinely multi-voltage system — the always-on domain at a different voltage than pwm_primary, say — would need set_level_shifter on that same boundary in addition to isolation, not instead of it; the two strategies aren't mutually exclusive, this specific example's supply choices just don't happen to trigger the second one.

The power-up sequence, for this exact domain​

Tracing The Power-Up Sequence's four steps against this block's real signals: assert pwm_pwr_en (the switch's EN) → wait for VDD_pwm_net to stabilize (controller logic, not a UPF construct) → pulse pwm_ret_restore to bring CTRL/PERIOD/DUTY back from the retention supply → release any block-local reset → de-assert pwm_iso_en, only now letting rdata and STATUS.running reflect real values again.

The power-down sequence, for this exact domain​

The walkthrough above only ever traces power-up. Powering PD_pwm back down runs the same four building blocks in the opposite order, for the same reason a save must happen before the data it's saving becomes unreliable: assert pwm_iso_en first (clamp rdata and STATUS.running to 0 before anything downstream can sample a mid-collapse value) → pulse pwm_ret_save (capture CTRL/PERIOD/DUTY into the retention flops while VDD_pwm_net is still valid) → only then de-assert pwm_pwr_en (drop VDD_pwm_net, since the switch's off_state {!EN} is what actually removes power). Save-before-power-off is non-negotiable — a retention flop asked to capture its data after its supply has already collapsed captures garbage, not state.

Power-up mirrors this exactly in reverse, which is why the two sequences read as inverses of each other: isolate → save → power off going down; power on → restore → de-isolate coming back up, with isolation being the very first thing enabled and the very last thing released on either side of the transition.

Closing the loop back to Verification​

This exact power intent is what Verification's power-aware verification page checks from the other side: static analysis confirms pwm_iso has exactly one correct isolation cell per boundary net and that pwm_pwr_en/pwm_iso_en sequencing is internally consistent; power-aware simulation exercises the real power-up/power-down transitions above and confirms CTRL/PERIOD/DUTY genuinely survive a full power cycle while STATUS.running correctly reads as unpowered/corrupt in between. Two topics, two different jobs, one shared piece of power intent.

This topic is complete

Foundations, all four control strategies, sequencing, and hierarchy — 10 pages, applied here to one real, complete example. With this, every topic on SiliconAcademia is a finished curriculum: Digital Design, Verilog, SystemVerilog, Testbench, UVM, Verification, and now UPF.