Skip to content

flow: every .odb has its .sdc - #4751

Draft
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:sdc-pair
Draft

oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:sdc-pair

Conversation

@oharboe

@oharboe oharboe commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Every step that writes N.odb now writes N.sdc beside it, and every step reads the .sdc beside the .odb it loads. The name of the .odb is the name of its constraints; nothing is inferred. Before synthesis the .sdc is the user's (1_2_yosys.sdc, a copy of SDC_FILE); from 1_synth on, every .odb has its own.

This follows the direction in The-OpenROAD-Project/OpenROAD#11260: carry the write_sdc output as text and read it back with read_sdc, the well-established path. No OpenROAD change is needed.

27 files, +88/−164.

Deleted

  • find_sdc_file: the glob of RESULTS_DIR, the reverse dictionary sort and "the greatest .sdc at or below this .odb's stem". open.tcl and generate_abstract.tcl read the .sdc with the same stem.
  • The second argument of load_design, at 21 call sites, each naming by hand which earlier step's .sdc it borrows.
  • 9 orfs_write_sdc calls in the stage scripts: orfs_write_db writes the pair, orfs_copy_db copies the pair.
  • flow_write_sdc and its 9 calls in flow.tcl: flow_write_db writes the pair.
  • In the Makefile, every .sdc but the user's: five empty-recipe X.sdc: X.odb rules, the three .sdc do-copy rules and do-copy's extension parameter, do-2_floorplan.sdc, do-5_route.sdc and do-6_1_fill.sdc in the stage recipes, and the .sdc prerequisites of the steps and stage targets. A step depends on its input .odb, and the .odb comes with its .sdc.

Fixed by construction

Which .sdc a step read was written down twice, once in its script and once in its Makefile prerequisites, and the two had drifted: 2_2_floorplan_macro declared 1_synth.sdc and macro_place.tcl read 2_1_floorplan.sdc. Now there is nothing to write down.

find_sdc_file picked by name order, so open_*/gui_* could pick a different stage's constraints:

opened .sdc read before .sdc read now
6_final.def 6_1_fill.sdc 6_final.sdc
5_1_grt-failed.odb 4_cts.sdc 5_1_grt-failed.sdc

The stem ends at the first dot of the file name, so 4_cts.odb, 4_cts.odb.def and 4_cts.odb.v all open with 4_cts.sdc.

load_design and open.tcl stop at read_sdc when the .sdc beside the input is missing; there is no fallback to search for. open.tcl reads the .sdc only with GUI_TIMING=1, as before.

Every substep opens on its own

make open_*, gui_* and any script that loads 3_3_place_gp.odb, say, get exactly the constraints that step ran with. The Makefile Contract already says a step with nothing to do "copies its .odb and .sdc through"; now every step does.

Paves the way for FLOW_INPUT_VARIANT

FLOW_INPUT_VARIANT (#4475) names the variant a stage reads its inputs from, so stages are shared between variants without copying results: one synthesis and floorplan feeding many experiments. #4475 had to teach find_sdc_file to rank candidates across two directories, and each read site had to remember to search them. With the pair, a stage's input is one stem: load_design is the single read of both files, so reading another variant's results is one path in one place.

Disk space

11 more .sdc files per flow, each the size of the design's constraints. Measured on sky130hd/aes:

size
20 .odb files 319.6 MB
of which byte-identical copies the flow already keeps (2_floorplan, 3_place, 4_cts, 5_route, 6_1_fill) 98.2 MB
one .sdc 36 KB
11 new .sdc files 0.40 MB

ORFS and OpenROAD have chosen maintainability over disk space repeatedly, and the same holds here:

For callers outside ORFS

load_design takes one argument. A script that passes two stops at the call with Tcl's wrong # args.

Testing

  • tclfmt/tclint 0.7.0 clean.
  • Integration test: orfs: every .odb has its .sdc (ORFS #4751), reference only bazel-orfs#1418 (closed, reference only), this change on top of the ORFS patches bazel-orfs carries, with the bazel-orfs side of the bump.
  • asap7/gcd through final, generate_abstract, generate_metadata and the floorplan estimate, built by bazel-orfs on top of the patches it carries, with and without this change: every stage's .odb and .sdc (1_synth to 6_final), 6_final.v, gcd.lef and gcd_typ.lib are byte-identical. 6_final.spef differs only in its *DATE line.
  • The same comparison shows the new substep .sdc files carry the constraints they replace: 2_floorplan.sdc, 3_place.sdc and 5_route.sdc now come from the last substep of their stage and are byte-identical to before.
  • The single-process flow, flow.tcl from the yosys netlist to 6_final with WRITE_ODB_AND_SDC_EACH_STAGE=0: all 20 .odb files get their .sdc; within a stage every .sdc is identical, and the constraints change once, at CTS.
  • make do-cts, then open_4_1_cts.odb, open_4_cts.odb.def and open_4_cts.odb.v with GUI_TIMING=1: each reads 4_1_cts.sdc or 4_cts.sdc.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies the handling of SDC (Synopsys Design Constraints) files throughout the physical design flow. It refactors the build system and TCL scripts to automatically associate each ODB design file with its corresponding SDC file using a new sdc_file_of utility. This change removes the need to explicitly pass, track, and copy SDC files as separate dependencies in the Makefile and as separate arguments in load_design and other helper procedures. I have no feedback to provide as there are no review comments to assess.

Every step that writes N.odb writes N.sdc beside it, and every step
reads the .sdc beside the .odb it loads. Before synthesis the .sdc is
the user's (1_2_yosys.sdc); from 1_synth on, every .odb has its own.

This deletes find_sdc_file, which picked an .sdc by name order and
gave open_*/gui_* another stage's constraints for a .def or a failed
.odb; the second argument of load_design, which named by hand which
earlier step's .sdc a script borrowed; the separate orfs_write_sdc and
flow_write_sdc calls, now part of orfs_write_db, orfs_copy_db and
flow_write_db; and every .sdc rule and prerequisite in the Makefile
except the user's, since a step's input .odb comes with its .sdc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant