The-OpenROAD-Project / The-OpenROAD-Project/OpenROAD
`diff_spef` cannot produce its documented output, and `calibrate_base_corner` is dropped
@AcKoucher is already working on this.
Since Aug 2, 2026.
- Dominant language
- Verilog
- Stars
- 3.1k
- Forks
- 1k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 136
Description
Version: OpenROAD 26Q3-104-gb5624809f2 (b562480), Linux x86-64, +GPU -GUI +Python.
Summary
While correlating a third-party parasitic extractor against OpenRCX we tried to use diff_spef,
and found that it cannot write diff_spef.out — the output its own documentation describes. Two
smaller things fell out alongside it. All three are verifiable by reading, and I think they share
one cause: the command has no test that exercises it.
I'd be glad to send a PR for any of these if the direction is agreed — I didn't want to guess at
the intended behaviour of (2).
1. diff_spef.out is never written
src/rcx/README.md says of diff_spef: "The output of this command is diff_spef.out". It is
not produced, and I believe no input can produce it.
The file handle is opened in exactly one place, extSpef::setUseIdsFlag
(src/rcx/src/extSpef.cpp:228):
void extSpef::setUseIdsFlag(const bool diff, const bool calib)
{
_diff = diff;
if (diff && !calib) {
_diffLogFP = fopen("diff_spef.log", "w");
...
_diffOutFP = fopen("diff_spef.out", "w");
Across the tree there are two calls:
| call site | arguments |
|---|---|
src/rcx/src/netRC.cpp:2116 |
setUseIdsFlag(false) |
src/rcx/src/extSpefIn.cpp:2478 |
setUseIdsFlag(true /*diff*/, true /*calib*/) |
The second is the only one that could open the handles, and it fails diff && !calib.
_diffOutFP is nullptr at declaration (include/rcx/extSpef.h:434) and is assigned nowhere
else, so every fprintf(_diffOutFP, …) in printDiff / printDiffCC is unreachable — which is
consistent with the command running to completion and writing nothing.
Observed: diff_spef -file ours.spef -r_res -r_cap -r_cc_cap exits 0, emits the usual
RCX-0463/RCX-0272/RCX-0292 messages, and produces no diff_spef.out or diff_spef.log in
the working directory.
Side observation, not reproduced: that same call sets _diff = true while leaving
_diffOutFP null. If any path reaches the printers with _diff set, it would write to a null
FILE*. I have not demonstrated such a path and am not claiming one exists — noting it only in
case it is relevant to the fix.
2. diff_spef drops opt.calibrate_base_corner
DiffOptions::calibrate_base_corner exists (include/rcx/ext_options.h:114) and is what
ultimately sets _db_calibbase_corner (src/extSpefIn.cpp:2379-2387), the flag guarding the
setUseIdsFlag(true, true) call above.
Ext::read_spef forwards it (src/ext.cpp:337):
opt.db_corner_name,
opt.calibrate_base_corner,
opt.spef_corner,
Ext::diff_spef passes nullptr in the same position (src/ext.cpp:387-389):
(char*) opt.db_corner_name,
nullptr,
opt.spef_corner,
So the option is defined, plumbed into DiffOptions, and discarded at the call site. I could not
tell from the code whether diff_spef is meant to accept it (the Tcl command doesn't expose it
either), which is why this is a report rather than a patch.
3. The rcx test helper for diff_spef has a bug, and nothing calls it
src/rcx/test/rcx_aux.py:120:
def diff_spef(
design, *, filename="", r_conn=False, r_res=False, r_cap=False, r_cc_cap=False
):
opts = rcx.DiffOptions()
opts.file = file # <-- `file`, not `filename`
file is not a parameter — on Python 3 this raises NameError on any call. Searching the tree,
nothing calls this helper, which is presumably why it has not surfaced. Fixing it to filename
and adding a regression that asserts diff_spef.out exists and has expected content would cover
(1) and (2) directly.
A crash we saw but cannot minimise
Separately, we hit a SIGSEGV in the same command on a large input:
rcx::NameTable::getDataId → rcx::extSpef::getDbInst → rcx::extSpef::getCapNodeId
→ rcx::extSpef::readDNet → rcx::Ext::diff_spef SIGSEGV
The input was a ~18 MB SPEF our own tool wrote, and it was malformed — so this is a robustness
report, not a correctness one. I have not been able to reduce it, and to save anyone repeating
my dead ends, these do not reproduce it (each errors cleanly with RCX-0044/RCX-0052, which
is the desired behaviour):
- a
*CAPnode label referencing a name-map id that is not defined (*0:clk_i); - a node label referencing a name-map id that resolves to a net rather than an instance;
- a node label referencing an id absent from the map entirely.
Happy to send the 18 MB input privately or attach a link if that is useful.
Why we were in here
We maintain an open rule-based extractor — https://github.com/vyges-tools/extract (Apache-2.0)
— and correlate it against OpenRCX on routed sky130 blocks. OpenRCX is our reference,
and diff_spef looked like the right way to let the incumbent define what a difference is rather
than writing our own comparator. We ended up comparing SPEF files directly instead. The findings
above are a by-product, offered back.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.