This is info on how to access design data through the OpenRoad python API. It includes both ORDB as well as the timing API. The ASP-DAC24 Tutorial also has a lot of good examples.
You should install OpenROAD or OpenLANE.
For the full API:
openroad -python
to expose the Python interface.
There is a lot of info in the tests here.
An example design is provided in ordb/final.tar.gz
that you can extract with:
tar zxvf ordb/final.tar.gz
import openroad
from openroad import Design, Tech, Timing
import rcx
import os
import odb
openroad.openroad_version()
odb_file = "final/odb/spm.odb"
def_file = "final/def/spm.def"
lef_files = ["/home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/techlef/sky130_fd_sc_hd__nom.tlef",
"/home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef"]
lib_files = ["/home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib"]
tech = Tech()
for lef_file in lef_files:
tech.readLef(lef_file)
for lib_file in lib_files:
tech.readLiberty(lib_file)
design = Design(tech)
You can either read the DEF or the ODB for the placement/routing:
design.readDef(def_file)
design.readDb(odb_file)
You can use extraction from either detailed routing or using the global routing. This TCL says to use either HPWL/placement or global routing:
estimate_parasitics
-placement|-global_routing
[-spef_file spef_file]
This is using detailed routing:
rcx.define_process_corner(ext_model_index=0, file="X")
ext_rules = "~/.volare/sky130A/libs.tech/openlane/rules.openrcx.sky130A.nom.spef_extractor"
#NOTE: This is position dependent
rcx.extract(ext_model_file=ext_rules,
corner_cnt=1,
max_res=50.0,
coupling_threshold=0.1,
cc_model=12,
context_depth=5,
debug_net_id="",
lef_res=False,
no_merge_via_res=False)
rcx.adjust_rc(res_factor,
cc_factor,
gndc_factor)
diff_spef -file 31-user_project_wrapper.spef
rcx.diff_spef(file=spef_file,
r_conn=False,
r_res=False,
r_cap=False,
r_cc_cap=False)
for net in design.getBlock().getNets():
print("**** ", net.getName())
for inst in design.getBlock().getInsts():
if "FILLER" in inst.getName():
continue
if "TAP" in inst.getName():
continue
if "decap" in inst.getMaster().getName():
continue
print(inst.getName(),
inst.getMaster().getName(),
design.isSequential(inst.getMaster()),
design.isInClock(inst),
design.isBuffer(inst.getMaster()),
design.isInverter(inst.getMaster()),
)
for outTerm in inst.getTerms():
if timing.isEndpoint(outTerm):
pass
if design.isInSupply(outTerm):
pass
if outTerm.isOutputSignal():
pass
if outTerm.isInputSignal():
pass
for lib in tech.getDB().getLibs():
for master in lib.getMasters():
print(master.getName())
for mterm in master.getMTerms():
print(" ", mterm.getName())
design.evalTclString("read_sdc {}".format("final/spm/sdc/spm.sdc")
timing = Timing(design)
See iterating below to find pins:
timing.getPinArrival(inTerm, Timing.Rise)
timing.getPinSlew(inTerm, Timing.Rise)
timing.getPinSlack(inTerm, Timing.Ries, Timing.Max)
timing.getNetCap(net, corner, Timing.Max)
timing.getNetCap(net, corner, Timing.Min)
for corner in timing.getCorners():
print(timing.staticPower(inst, corner),
timing.dynamicPower(inst, corner),
)
for lib in tech.getDB().getLibs():
for master in lib.getMasters():
print(master.getName())
for mterm in master.getMTerms():
print(" ", mterm.getName())
for m in timing.getTimingFanoutFrom(mterm):
print(" -> ", m.getName())
The best way I've found to get additional API info is to set a breakpoint in your code and then use auto-complete to see what is available. Set a breakpoint:
for lib in tech.getDB().getLibs():
for master in lib.getMasters():
print(master.getName())
for mterm in master.getMTerms():
print(" ", mterm.getName())
breakpoint()
and run your script:
OpenLane Container (2.2.9):/home/USER/class/chip-tutorials% openroad -python load.py
OpenROAD edf00dff99f6c40d67a30c0e22a8191c5d2ed9d6
Features included (+) or not (-): +Charts +GPU +GUI +Python
This program is licensed under the BSD-3 license. See the LICENSE file for details.
Components of this program may be licensed under more restrictive licenses which must be honored.
[WARNING ORD-0039] .openroad ignored with -python
[INFO ODB-0227] LEF file: /home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/techlef/sky130_fd_sc_hd__nom.tlef, created 14 layers, 25 vias
[WARNING ODB-0220] WARNING (LEFPARS-2008): NOWIREEXTENSIONATPIN statement is obsolete in version 5.6 or later.
The NOWIREEXTENSIONATPIN statement will be ignored. See file /home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef at line 2.
[INFO ODB-0227] LEF file: /home/mrg/.volare/sky130A/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef, created 437 library cells
[ERROR STA-0340] cannot open 'final/spm/sdc/spm.sdc'.
sky130_fd_sc_hd__a2bb2o_1
A1_N
> /home/mrg/class/chip-tutorials/load.py(31)<module>()
-> for mterm in master.getMTerms():
(Pdb)
At the debug prompt, you can use the "p" command like this and press tab or indent twice to autocomplete:
(Pdb) p mterm.get
mterm.getBBox mterm.getDiffArea mterm.getMPins mterm.getName mterm.getSigType
mterm.getConstName mterm.getIndex mterm.getMTerm mterm.getOxide2AntennaModel mterm.getTargets
mterm.getDefaultAntennaModel mterm.getIoType mterm.getMaster mterm.getShape
(Pdb) p mterm.get
Note that it doesn't do it unless you print. So this does not work:
(Pdb) mterm.get