Power States
Power Domains and Supplies established what a supply set is. This page covers what values it's actually allowed to take on — and, just as importantly, what happens when the design reaches a combination that isn't allowed.
Declaring a power state
add_power_state PD_pwm.primary \
-state {PWM_ON -logic_expr {pwr_ctrl==1} \
-supply_expr {(power==FULL_ON,1.0) && (ground==FULL_ON)} \
-simstate NORMAL} \
-state {PWM_OFF -logic_expr {pwr_ctrl==0} \
-supply_expr {(power==FULL_ON,0) && (ground==FULL_ON,0)} \
-simstate CORRUPT}
add_power_state names each legal combination a supply set (or domain) can be in — PWM_ON here means "powered at 1.0V, with pwr_ctrl asserted"; PWM_OFF means the supply is present in the network but delivering no voltage. -logic_expr ties the state to a real control signal's value; -supply_expr ties it to the actual voltage/ground condition. Together, the full set of -state entries for an object forms its power state table (PST).
PD_pwm.primary power state table:
Legal states are enforced, not just documented
Every named state is legal by default unless explicitly marked -illegal — and a power-aware simulator is required to raise a runtime error the instant the design reaches an illegal state, or makes an illegal transition between two legal ones. An unnamed combination — anything the PST simply never described — is illegal automatically, with no need to enumerate every possible bad combination by hand. This turns the PST from documentation into an active check: a bug that drives a supply into a combination nobody intended shows up immediately during power-aware simulation, not silently.
-simstate: a separate axis from legal/illegal
Whether a state is legal and how logic behaves in simulation while in that state are two different questions, deliberately kept as two separate options rather than conflated into one:
NORMAL— the supply is fully valid; logic in this state simulates exactly as ordinary RTL would.CORRUPT— the supply can't reliably hold a value (power is off or invalid); logic in this state simulates as unknown, modeling the real hardware reality that a powered-down flop's contents aren't dependably anything.- Intermediate values exist between the two, for states with partial validity — a supply ramping up or down, or a retention state where some logic (the retained flops) stays valid while the rest of the domain doesn't. One named intermediate value,
CORRUPT_ON_ACTIVITY, models a specific, common case of this: a signal holds its last stable value indefinitely, but corrupts the instant any of its dependent inputs actually switches — the behavior of a marginal/degraded-voltage state where a static value survives but any toggle doesn't.
PWM_OFF above is legal (it's a real, expected state the design enters) but -simstate CORRUPT — the distinction being the difference between "this can happen" and "trust what comes out of it while it's happening."
UPF's own default changed between versions, and it's a real migration trap: UPF 1.0 defaulted a created supply to the ON state, so early flows often never bothered calling supply_on explicitly. UPF 2.0 flipped that default to OFF — meaning every power domain starts in a CORRUPT simstate until something explicitly turns its supply on. A UPF 1.0-era file migrated to a UPF 2.0 tool without adding explicit supply_on calls will silently simulate as if every domain starts powered down.
What's next
With domains, supplies, and legal states established, Section B covers the four strategies that actually keep a design correct as it moves between those states — starting with the one every unsynchronized domain boundary needs: isolation.