Skip to main content

Power Analysis

rb power runs OpenROAD report_power on a mapped design and reports total, internal, switching, and leakage power. FPGA runs report Vivado power directly and do not use this command.

Install OpenROAD​

OpenROAD 25Q1 or newer must be on PATH or configured under cfg-power-tools. Only tool: openroad is supported; other tools report SKIP.

The run's platform names a cfg-pnr-platforms entry that supplies the PDK and Liberty corner; see Place-and-Route: Configure the physical platform. A platform with corners: analyses every listed corner in one session; see Place-and-Route: Sign off at several corners.

Choose the design source​

SourceInputTiming and parasiticsRequired upstream runs
netlist-source: synth (default)synth_netlist.vUser SDC, no wire parasitics or clock treerb synth
netlist-source: pnr<top>.routed.odbRouted SDC, CTS, and parasiticsrb synth, then rb pnr

The synth source suits early leakage and activity comparisons but underestimates switching, which lacks wire capacitance. Use pnr for a post-route estimate; if the routed ODB is missing, rerun rb pnr.

Extracted parasitics​

A pnr source reads the P&R run's extracted <top>.routed.spef when the PDK sets rcx-rules. Otherwise it estimates parasitics from global routing, with the PDK's layer-rc-tcl sourced first when set. That file's contents are part of the run's configuration digest, so editing it makes a new experiment. A configured layer-rc-tcl or platform-tcl missing from disk fails the run at setup.

The SPEF is used only if its pnr.tcl contains write_spef and the SPEF is no older than that pnr.tcl. Otherwise the run logs a power.spef_rejected warning naming the reason and uses the estimate. The parasitics result field (spef or estimated) and the summary's Parasitics column show which was used, and one ODB measured both ways counts as two experiments.

Extraction usually raises switching power and lowers slack compared with the estimate.

Define power runs​

rtl-buddy-filetype: power_config

runs:
- name: demo_power_static
desc: Static post-synthesis power
tool: openroad
mode: static
synth: demo_synth_nangate45
synth-path: ../../synth/demo/synth.yaml
phys-run: demo_synth_nangate45
constraints: ../../synth/demo/constraints.sdc
platform: nangate45_typ
reglvl: 1000

- name: demo_power_saif
desc: Simulation-driven post-route power
tool: openroad
mode: dynamic
netlist-source: pnr
pnr: demo_pnr_nangate45
pnr-path: ../../pnr/demo/pnr.yaml
platform: nangate45_typ
activity:
saif: ../../verif/demo/artefacts/csr_smoke/dump.saif
scope: tb_top/u_dut
reglvl: 1000

Paths resolve from power.yaml.

  • A synth source requires synth, synth-path and constraints.
  • A pnr source requires pnr and pnr-path. It uses the routed SDC unless constraints overrides it.
  • phys-run is optional; see Pair the model with a synthesis run.

All fields are in YAML Formats: power.yaml.

Select activity​

Mode and fieldsApplied activity
mode: staticNo activity command
mode: dynamic with activity.saifPer-signal SAIF activity
mode: dynamic with activity.vcdPer-signal VCD activity
mode: dynamic with no traceSynthetic toggle rate and static probability, set globally and on the primary inputs

activity.saif and activity.vcd are mutually exclusive. Set activity.scope only with a trace, to the hierarchy containing the design, such as tb_top/u_dut. Synthetic defaults are a 0.1 toggle rate and 0.5 static probability; override them with activity.default-toggle-rate and activity.default-static-prob. The inputs take the same values because OpenSTA reports inf or NaN power downstream of an input with no activity that it does not time, such as a false-pathed input.

Before applying any activity, the script runs sta::update_generated_clks after read_sdc. OpenSTA leaves a generated clock at period 0 until its waveform is derived, and report_power does not derive it, so an activity relative to that clock, such as input activity on a port whose set_input_delay names a forwarded clock, would otherwise be infinite.

Capture SAIF activity​

Convert a debug waveform with rb saif, then run the analysis:

rb -M debug test csr_smoke
rb saif verif/demo/artefacts/csr_smoke/dump.fst \
verif/demo/artefacts/csr_smoke/dump.saif
rb power demo_power_saif -c power/demo/power.yaml -l 1000

The converter accepts FST or VCD. If the trace starts at the testbench, set activity.scope to the design top.

Give hard macros a library​

The platform corner characterises standard cells only. A hard macro such as an SRAM, PLL or hardened partition needs its own Liberty. Without one, the macro stays in power_instances.rpt but contributes exactly zero:

Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%

The power run inherits the libraries of the run it references, so the usual case needs no configuration:

netlist-sourceInherited from the upstream entry
pnrlib-paths
synthlib-paths and lef-paths

A hardened block named under blocks: is resolved too. A block with no abstract fails the run before OpenROAD starts and names the block. Do not add the abstract's .lib to lib-paths: it has timing arcs but no power tables, and loading it makes OpenROAD ignore SAIF, VCD and set_power_activity values on the block's outputs. Without it the block reports 0 W and appears in the unpowered-cell warning.

To add a library only the analysis needs, such as a corner the upstream run was not routed against, set lib-paths on the power.yaml entry:

runs:
- name: demo_power_macro
netlist-source: pnr
pnr: demo_pnr
pnr-path: ../../pnr/demo/pnr.yaml
platform: sky130hd_tt
lib-paths: ["../../pdk/sram/sram_TT_1p8V_25C.lib"]

Paths resolve from power.yaml.

Read the unpowered-cell warning​

An instance whose master no Liberty covers reports 0.00e+00 in every column, the same as a cell that burns nothing. A run that finds one warns:

power run "demo_power_macro": 1 instance(s) have no Liberty power data and report 0 W — sram_32x256.

--machine output adds unpowered_cells, unpowered_cell_count and unpowered_instance_count; all three are absent when nothing was found. To fix it, supply the cell's Liberty as described in Give hard macros a library.

The verdict does not change: the reported watts are a real measurement of everything that had a library, and a design with a LEF-only macro on purpose, such as a fakeram45 placeholder, could not otherwise pass. Gate on unpowered_cell_count if your flow signs off on power. Fill cells listed in the PDK's fill-cells are not reported.

Run power analysis​

rb power --list -c power/demo/power.yaml
rb power demo_power_saif -c power/demo/power.yaml
rb power-regression -c power_regression.yaml -l 1000

A regression manifest lists power configs relative to itself:

rtl-buddy-filetype: power_reg_config
power-configs:
- power/block_a/power.yaml
- power/block_b/power.yaml

OpenROAD runs on one thread unless the run sets threads: to a positive integer or auto. See OpenROAD threads.

Interpret results​

The summary names the design source and activity source, then reports total, internal, switching, and leakage power in SI units.

On a multi-corner platform the reported watts are those of the worst corner, the one with the highest design total. worst_corner names it, corners holds every corner's four figures, and power.rpt, power_instances.rpt and the physical model describe that corner.

A run passes when OpenROAD exits 0, emits no [ERROR ...] line, and produces a parseable Total row in power.rpt; on a multi-corner platform every corner's report must parse. It skips when filtered by reglvl or when its tool has no backend.

Pair the model with a synthesis run​

A complete physical model needs the synthesis run's per-module cells and area and the power run's per-instance watts in one artefact directory. Each run publishes into its own directory by default. If the suites are split into synth/ and power/, or the runs have different names, the halves land apart: rb phys instance exits 2 on the synthesis directory, and rb phys module finds no modules in the power run's.

phys-run pairs them explicitly:

runs:
- name: demo_power_static
synth: demo_synth_nangate45
synth-path: ../../synth/demo/synth.yaml
phys-run: demo_synth_nangate45
  • The value names a run in the synth.yaml that synth-path points at. The model and manifest are published into that run's artefacts/<run>/; the log, reports and netlist copy stay in the power run's own directory. The synthesis directory need not exist yet.
  • A phys-run that names no entry in synth.yaml, or resolves outside the project, is a configuration error.
  • phys-run requires netlist-source: synth.
  • One directory holds one power half. Two power runs with the same phys-run, such as a static and a dynamic analysis of one design, overwrite each other. Leave phys-run off runs whose breakdowns must stay apart.
  • Removing or changing phys-run leaves the old directory's power half in place. Rerun the analysis or delete the directory.

phys-run does not force a merge. The halves merge only when the synthesis and the power run used the same netlist. Otherwise the run warns and publishes its half alone; rerun the synthesis and the power analysis over one netlist. A later synthesis likewise keeps the power rows only if its netlist is unchanged. A pnr source never merges. See Read a model with only one half.

Inspect artefacts​

Outputs land under <power-dir>/artefacts/<run>/:

FilePurpose
power.tcl, power.logGenerated OpenROAD script and its output
power.rptRaw report_power report (worst corner on a multi-corner platform)
power.<corner>.rptEach corner's report, multi-corner platforms only
power_netlist.vThis run's copy of the upstream netlist, the file OpenROAD reads
power_instances.rptRaw report_power -instances, one line per leaf instance
phys-model.json, phys-manifest.jsonPhysical model and its manifest; query with rb phys (Physical Metrics)

With phys-run set, the model and manifest are written to the synthesis run's directory instead.

An FPGA run and a power run must not share a name within one suite. Both own artefacts/<name>/power.rpt, and the second to run overwrites the first.

Troubleshooting​

Read power.log for tool and input errors, then power.rpt for missing or malformed totals. A failed run deletes power.rpt and the netlist copy, so it never leaves an earlier run's numbers.

  • N instance(s) have no Liberty power data and report 0 W: see Read the unpowered-cell warning.
  • N configured macro input(s) not on disk: the run stops. Fix the listed lib-paths or lef-paths on this entry or the upstream run.
  • Total line of report_power output is NaN/inf: OpenSTA converted an activity against a zero clock period. Check that every clock the SDC's I/O delays reference has a finite period; create_generated_clock clocks are derived before the activity is read.
  • power.spef_rejected: the SPEF is unreadable or stale and the estimate was used. Rerun rb pnr, then the power run.
  • phys-model.json has no per-instance breakdown: the per-instance report was missing or unreadable. Totals are still recorded and the run passes, but rb phys instance has nothing for it.
  • phys-model.json was not written: publishing failed. Any model in the directory belongs to an earlier run.
  • Previous run's per-instance rows could not be withdrawn: the run stops rather than leave stale rows over cleared reports. Fix the error the message names and rerun.