variables: FLOW_INPUT_VARIANT, read inputs from another variant - #4477
variables: FLOW_INPUT_VARIANT, read inputs from another variant#4477oharboe wants to merge 1 commit into
Conversation
FLOW_VARIANT names the directory a run writes to. It also names the directory a run reads from, which means a variant that wants to reuse an upstream variant's results has to physically copy them into its own directory first. Sharing an expensive front end across experiments — one synthesis, one floorplan, many routing variants — is a `cp -r` per fork today. Split the two. FLOW_INPUT_VARIANT names the variant a run reads from and gives INPUT_RESULTS_DIR, INPUT_LOG_DIR, INPUT_REPORTS_DIR and INPUT_OBJECTS_DIR alongside the existing output directories. It defaults to FLOW_VARIANT, so every INPUT_*_DIR expands to a string identical to its *_DIR counterpart and an unchanged run is unchanged. Reads resolve against a search path: RESULTS_DIR first, INPUT_RESULTS_DIR second. RESULTS_DIR has to come first because a stage runs several steps in one process — do-place writes 3_1_place_gp_skip_io.odb and the next step reads it back — and a file this run just wrote must win over the upstream variant's copy of it. orfs_input_path and orfs_input_glob in util.tcl are the search; every write still goes straight to RESULTS_DIR. load_design is the chokepoint: all 18 stage scripts hand it a bare basename, so routing it through orfs_input_path covers the whole flow. The remaining reads are the AUTO_MEMORIES globs, find_sdc_file, the abstract's .spef, yosys_load's netlist, and genMetrics' log/report/ result directories. find_sdc_file's candidate ordering now compares basenames rather than full paths. With one directory the two are equivalent, since every candidate shares a prefix; with two, the directory prefix would otherwise decide which .sdc wins. The Makefile's prerequisite graph is deliberately untouched: it still names $(RESULTS_DIR). A forked variant is driven through the do- targets, which is what the flow.sh path does anyway. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
There was a problem hiding this comment.
Code Review
This pull request introduces the FLOW_INPUT_VARIANT variable, allowing stages to read inputs from a different variant directory than the one they write to, which facilitates sharing upstream results without copying directories. The changes include documentation updates, new path-resolution helper procedures in util.tcl, and updates across various Tcl scripts and Makefiles to use these helpers. Feedback on the changes suggests clarifying a potentially confusing circular dependency in the documentation's Mermaid diagram and caching the result of orfs_input_path in generate_abstract.tcl to avoid redundant filesystem searches.
| ```mermaid | ||
| flowchart LR | ||
| subgraph base["FLOW_VARIANT=base — shared front end"] | ||
| S["1_synth"] --> F["2_floorplan"] --> P["3_place"] --> C["4_cts"] | ||
| end | ||
|
|
||
| subgraph io["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=io"] | ||
| Q["quick pin placement"] --> IOTCL["io.tcl"] | ||
| end | ||
|
|
||
| subgraph main["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=main"] | ||
| G["5_grt"] --> R["5_route"] --> FIN["6_final"] | ||
| end | ||
|
|
||
| subgraph hi["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=high_effort"] | ||
| G2["5_grt (higher effort)"] --> R2["5_route"] --> FIN2["6_final"] | ||
| end | ||
|
|
||
| F -. "reads base results" .-> Q | ||
| C -. "reads base results" .-> G | ||
| C -. "reads base results" .-> G2 | ||
| IOTCL -- "IO_CONSTRAINTS" --> F | ||
| ``` |
There was a problem hiding this comment.
The Mermaid diagram illustrating the use of FLOW_INPUT_VARIANT for a custom pin layout flow is a bit confusing. The arrow IOTCL -- "IO_CONSTRAINTS" --> F suggests a circular dependency, as the base variant's floorplan (F) seems to depend on an output (IOTCL) from the io variant, which itself depends on F.
The accompanying text says "The main flow then re-runs from floorplan with IO_CONSTRAINTS pointing at it". This implies a new floorplan run in a separate variant (e.g., main_with_io), which would read synthesis from base and io.tcl from io.
To improve clarity, consider adjusting the diagram to better reflect this. For example, you could introduce a new floorplan node in a different variant that takes IOTCL as an input, rather than having the arrow point back to the original F in the base variant.
| if { $design_stage >= 6 && [file exists [orfs_input_path $stem.spef]] } { | ||
| log_cmd read_spef [orfs_input_path $stem.spef] |
There was a problem hiding this comment.
The function orfs_input_path is called twice for the same file, $stem.spef. To improve readability and avoid a redundant file system search, you could store the result in a variable.
if { $design_stage >= 6 && [file exists [set spef_path [orfs_input_path $stem.spef]]] } {
log_cmd read_spef $spef_path
|
duplicate |
FLOW_VARIANTnames the directory a run writes to. It also names the directory a run reads from, so a variant that wants to reuse an upstream variant's results has to physically copy them into its own directory first. Sharing an expensive front end across experiments — one synthesis, one floorplan, many routing variants — is acp -rper fork today.The change
FLOW_INPUT_VARIANTnames the variant a run reads from, and givesINPUT_RESULTS_DIR,INPUT_LOG_DIR,INPUT_REPORTS_DIRandINPUT_OBJECTS_DIRalongside the existing output directories:It defaults to
FLOW_VARIANT, so everyINPUT_*_DIRexpands to a string identical to its*_DIRcounterpart and an unchanged run is unchanged.The same mechanism lets one fork produce an input for another — a pin-placement flow running as
FLOW_INPUT_VARIANT=base FLOW_VARIANT=ioreads the shared floorplan, writesio.tclinto theiovariant, and the main flow re-runs from floorplan withIO_CONSTRAINTSpointing at it, still reusing the samebasesynthesis.docs/user/FlowVariables.mddocuments this with a diagram.Search path, not a switch
Reads resolve against
RESULTS_DIRfirst andINPUT_RESULTS_DIRsecond. That ordering is required, not cosmetic: a stage runs several steps in one process —do-placewrites3_1_place_gp_skip_io.odband the next step reads it back — so a file this run just wrote must win over the upstream variant's copy.orfs_input_path/orfs_input_globinutil.tclare the whole mechanism; every write still goes straight toRESULTS_DIR.What is touched
load_designis the chokepoint — all 18 stage scripts hand it a bare basename, so routing it throughorfs_input_pathcovers the flow. The remaining reads are theAUTO_MEMORIESglobs,find_sdc_file, the abstract's.spef,yosys_load's netlist, and genMetrics' log/report/result directories.find_sdc_file's candidate ordering now compares basenames rather than full paths. With one directory the two are equivalent, since every candidate shares a prefix; with two, the directory prefix would otherwise decide which.sdcwins.The Makefile's prerequisite graph is deliberately untouched: it still names
$(RESULTS_DIR). A forked variant is driven through thedo-targets. Teaching the prerequisites to search a second directory is a separate,vpath-shaped change.Testing
Exercised end to end through bazel-orfs, which is the heaviest user of cross-variant reads — it runs every stage of every design out of one variant's directory into another's, and until now did so by
mv-ing inputs before eachmake. With this patch that renaming is deleted outright and the whole suite (123 tests) passes, so every test in it now runs through this code path.Added there alongside it: a variant forked at cts off a shared
placestage, asserting its config names the input variant, that its action inputs carry the upstream variant's ODB and no copy under its own results path, and that it builds. All three fail withoutFLOW_INPUT_VARIANT.