Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
58fab1c
synth: single writer for 1_synth.sdc
oharboe Jul 6, 2026
840af79
Merge remote-tracking branch 'origin/master' into synth-single-writer…
oharboe Jul 7, 2026
6da7ca5
bazel: mirror tools/OpenROAD's rules_pycross Python 3.8 workaround
oharboe Jul 7, 2026
1268384
flow: gate every stage .odb/.sdc file product on WRITE_ODB_AND_SDC_EA…
oharboe Jul 7, 2026
506260d
synth: keep the 1_synth.odb/.sdc writes behind WRITE_ODB_AND_SDC_EACH…
oharboe Jul 7, 2026
f75083e
flow: single-process flow.tcl + gcd equivalence test with no-write as…
oharboe Jul 7, 2026
640e205
flow: fix the grt-stage single-process divergence via an OpenSTA patch
oharboe Jul 7, 2026
87b6286
flow: fix the route-stage single-process divergence via a drt patch
oharboe Jul 7, 2026
a9deded
flow: route stage byte-identical; the residue was stale bterm access …
oharboe Jul 7, 2026
4567701
flow: split final_report.tcl around the 6_final.odb write
oharboe Jul 7, 2026
abb514c
flow: file join for single-process flow output paths
oharboe Jul 8, 2026
7780f82
flow: don't exit the process on SKIP_DETAILED_ROUTE
oharboe Jul 8, 2026
898c39f
drt: strict weak ordering for the canonical via sort
oharboe Jul 8, 2026
0b58bdc
bazel: patch sed's gnulib memchr for glibc >= 2.42
oharboe Jul 8, 2026
93b9992
deps: bump OpenROAD to master; adopt the hermetic-llvm toolchain
oharboe Jul 8, 2026
f3fcd90
flow: update rules-base.json for QoR shift from the OpenROAD bump
oharboe Jul 8, 2026
63e365c
update OR
maliberty Jul 8, 2026
ffdf48c
Merge remote-tracking branch 'origin' into synth-single-writer-1synth…
maliberty Jul 8, 2026
adaa6a9
bazel: drop OpenROAD pinning, keep local_path_override
oharboe Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ common --registry=https://raw.githubusercontent.com/oharboe/bazel-central-regist
build --incompatible_strict_action_env
build --cxxopt "-std=c++20" --host_cxxopt "-std=c++20"

# Refuse to autodetect a local C++ toolchain (/usr/bin/gcc); the hermetic
# toolchain must win resolution. Mirrors tools/OpenROAD/.bazelrc.
common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1

# Launch py_binary via a shell stub instead of rules_python's legacy python
# stub, whose '#!/usr/bin/env python3' shebang needs a host python3 before
# the hermetic interpreter takes over. Mirrors tools/OpenROAD/.bazelrc.
common --@rules_python//python/config_settings:bootstrap_impl=script

# Don't track MODULE.bazel.lock. Resolved versions ride along with the
# pinned BCR + git_override(commit=…) coordinates in MODULE.bazel and
# downstream cache hits are what we actually care about. Tracking the
Expand Down
81 changes: 71 additions & 10 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,64 @@ bazel_dep(name = "rules_shell", version = "0.6.1")
# our MODULE.bazel doesn't need to be patched at non-root consumption
# time.

bazel_dep(name = "toolchains_llvm", version = "1.5.0", dev_dependency = True)
# hermetic-llvm (BCR module "llvm") provides statically linked LLVM
# binaries and a zero-sysroot cc_toolchain: no host compiler, linker or
# /usr/include involved, so host glibc changes cannot break the build.
# Mirrors tools/OpenROAD/MODULE.bazel (its llvm dep is dev-only, so it
# does not propagate here).
bazel_dep(name = "llvm", version = "0.8.11", dev_dependency = True)

# The gnulib-based GNU tools (sed, gawk, m4, bison) vendor wrapper
# headers that must shadow libc headers, which breaks against
# hermetic-llvm's explicit libc -isystem entries (BCR #7642). Mirror
# tools/OpenROAD's fixed-version overrides (single_version_override is
# root-honored only); drop each when tools/OpenROAD drops its copy.
#
# sed is transitive (bazel-orfs -> abc -> readline -> ncurses -> sed);
# 4.9.bcr.5 carries the upstream fix (BCR #7915).
single_version_override(
module_name = "sed",
version = "4.9.bcr.5",
)

# gawk is transitive (abc -> ncurses -> gawk; yosys -> gawk);
# 5.3.2.bcr.7 carries the upstream fix (BCR #7989).
single_version_override(
module_name = "gawk",
version = "5.3.2.bcr.7",
)

# m4 is transitive (rules_bison/rules_flex -> m4).
single_version_override(
module_name = "m4",
version = "1.4.21.bcr.4",
)

# bison is transitive (rules_bison -> bison). 3.8.2.bcr.7 fixes lib/
# but src/ still picks up raw libc headers; the patch restores gnulib
# wrapper-header precedence via -I (to be proposed upstream as
# 3.8.2.bcr.8, then drop).
single_version_override(
module_name = "bison",
patch_strip = 1,
patches = [
"//patches/bison:0001-gnulib-wrapper-headers-use-I-not-isystem.patch",
],
version = "3.8.2.bcr.7",
)

# tclZipfs.c's '#include "crypt.h"' picks up glibc's crypt.h instead of
# the vendored minizip one when glibc headers are explicit -isystem
# directories (hermetic-llvm zero-sysroot toolchain). Drop when fixed
# in a tcl_lang BCR release.
single_version_override(
module_name = "tcl_lang",
patch_strip = 1,
patches = [
"//patches/tcl_lang:0001-tclZipfs-include-vendored-minizip-crypt.h-by-path.patch",
],
)

bazel_dep(name = "openroad", dev_dependency = True)
local_path_override(
module_name = "openroad",
Expand Down Expand Up @@ -68,20 +125,24 @@ git_override(

# --- Extensions ---

llvm = use_extension(
"@toolchains_llvm//toolchain/extensions:llvm.bzl",
"llvm",
register_toolchains(
"@llvm//toolchain:all",
dev_dependency = True,
)
llvm.toolchain(
llvm_version = "20.1.8",
)
use_repo(llvm, "llvm_toolchain")

register_toolchains(
"@llvm_toolchain//:all",
# sv-lang (via tools/OpenROAD) pulls in rules_pycross, whose toolchain
# extension fails on Python 3.8 (transitively registered via or-tools ->
# pybind11_abseil, dropped from rules_python 2.0.0's MINOR_MAPPING).
# pycross.configure_environments is root-honored only, so the workaround
# must be mirrored here from tools/OpenROAD/MODULE.bazel.
bazel_dep(name = "rules_pycross", version = "0.8.1", dev_dependency = True)

pycross = use_extension(
"@rules_pycross//pycross/extensions:pycross.bzl",
"pycross",
dev_dependency = True,
)
pycross.configure_environments(python_versions = ["3.13"])

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
Expand Down
6 changes: 6 additions & 0 deletions bazel/slang-compat/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Placeholder directory for the @slang alias build file to internally
manifest. tools/OpenROAD's MODULE.bazel declares
new_local_repository(name="slang", path="bazel/slang-compat"); the
relative path resolves against the root workspace, so when ORFS is the
root module consuming openroad via git_override the directory must
exist here too. Mirrors tools/OpenROAD/bazel/slang-compat.
167 changes: 166 additions & 1 deletion flow/designs/asap7/gcd/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,168 @@
load("@bazel-orfs//:openroad.bzl", "orfs_run")
load("@orfs_designs//:designs.bzl", "DESIGNS")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//flow/designs:design.bzl", "design")

design(config = "config.mk")
# SYNTH_USE_SYN is make-only for now: bazel-orfs's synth stage always
# runs the yosys flow and neither stages the Verilog sources nor sets
# VERILOG_FILES for the OpenROAD synthesis step, so the built-in
# synthesizer opt-in must not reach the bazel arguments.
design(
config = "config.mk",
local_arguments = ["SYNTH_USE_SYN"],
)

# Stage-boundary .odb/.sdc stems shared by the normal per-stage flow
# targets and the single-process flow below; the gcd_single_flow_test
# suite compares each of these files pairwise between the two flows.
SINGLE_FLOW_STAGES = {
"synth": "1_synth",
"floorplan": "2_floorplan",
"place": "3_place",
"cts": "4_cts",
"grt": "5_1_grt",
"route": "5_route",
"final": "6_final",
}

# Substep files the single-process flow also writes, declared so the
# action keeps them and a human can inspect them on failure.
SINGLE_FLOW_EXTRA_OUTS = [
"2_1_floorplan.odb",
"2_1_floorplan.sdc",
"2_2_floorplan_macro.odb",
"2_3_floorplan_tapcell.odb",
"2_4_floorplan_pdn.odb",
"3_1_place_gp_skip_io.odb",
"3_2_place_iop.odb",
"3_3_place_gp.odb",
"3_4_place_resized.odb",
"3_5_place_dp.odb",
"4_1_cts.odb",
"5_2_route.odb",
"5_3_fillcell.odb",
"6_1_fill.odb",
"6_1_fill.sdc",
]

# The whole flow, yosys netlist through finish, as one Tcl script in a
# single OpenROAD process (scripts/flow.tcl) with
# WRITE_ODB_AND_SDC_EACH_STAGE=0: the stage scripts write no .odb/.sdc
# files (flow.tcl errors if one does), the top level writes every file
# the per-stage flow produces via explicit write_db/write_sdc. The
# synth stage config only carries synth-scoped variables, so the
# design's full argument set rides along; FLOW_VARIANT=single keeps the
# output paths clear of the regular stage targets' declared outputs in
# this package.
orfs_run(
name = "gcd_single_flow",
src = ":gcd_synth",
outs = [
"results/asap7/gcd/single/{}.{}".format(stem, ext)
for stem in SINGLE_FLOW_STAGES.values()
for ext in [
"odb",
"sdc",
]
] + [
"results/asap7/gcd/single/" + name
for name in SINGLE_FLOW_EXTRA_OUTS
],
arguments = {
k: v
for k, v in DESIGNS["asap7/gcd"]["arguments"].items()
if k != "SYNTH_USE_SYN"
} | {
"FLOW_VARIANT": "single",
},
script = ":single_flow.tcl",
variant = "single",
)

# Normal-flow stage outputs, one filegroup per compared file.
[
filegroup(
name = "gcd_base_{}_{}".format(stage, ext),
srcs = [":gcd_" + stage],
output_group = "{}.{}".format(stem, ext),
)
for stage, stem in SINGLE_FLOW_STAGES.items()
for ext in [
"odb",
"sdc",
]
]

# Byte-compare each stage boundary's .odb/.sdc between the per-stage
# flow and the single-process flow: equal files prove the
# single-process mode is equivalent to the per-stage flow, not merely
# that it runs to completion. check_same.sh takes file pairs:
# file_a file_b ... (.sdc pair first: check_same.sh stops at a binary
# diff, and the .sdc verdict should be reported before that).
#
# The synth through grt boundaries are byte-identical. The grt stage
# used to diverge (an extra repair_timing buffer): STA endpoint state
# for CTS dummy-load pins differed between a process that inserted them
# and a process that read the same design from disk, and
# resistance-aware global routing consumed the resulting bogus net
# slacks — fixed by patches/openroad/0001-sta-register-new-instance-
# pin-vertices-as-endpoints.patch.
#
# The route stage used to route differently in-process (net/instance
# iteration order and via emission order in drt reflected the process
# history) — fixed by patches/openroad/0002-drt-make-incremental-
# design-updates-match-a-fresh-read.patch; the routed layout is now
# identical (equal DEF).
#
# The route .odb byte difference was NOT an odb id/freelist issue
# (free lists serialize and reload): the per-stage flow accumulated
# stale block-terminal access points on every pin access rerun — fixed
# by patches/openroad/0003-drt-do-not-duplicate-bterm-access-points.
# patch; route is byte-identical now.
#
# The final stage used to diverge because the per-stage flow writes
# 6_final.odb mid-final_report (before the RCX extraction reorders
# every dbWire via odb orderWires) while this flow wrote at end of
# script — resolved by splitting final_report.tcl around its write so
# flow.tcl writes at the same point. All seven stage boundaries are
# byte-identical between the two flows.
[
sh_test(
name = "gcd_single_flow_{}_test".format(stage),
srcs = ["@openroad//test/orfs:check_same.sh"],
args = [
arg
for ext in [
"sdc",
"odb",
]
for arg in [
"$(location :gcd_base_{}_{})".format(stage, ext),
"$(location :results/asap7/gcd/single/{}.{})".format(stem, ext),
]
],
data = [
":gcd_base_{}_{}".format(stage, ext)
for ext in [
"sdc",
"odb",
]
] + [
":results/asap7/gcd/single/{}.{}".format(stem, ext)
for ext in [
"sdc",
"odb",
]
],
tags = ["orfs"],
)
for stage, stem in SINGLE_FLOW_STAGES.items()
]

test_suite(
name = "gcd_single_flow_test",
tests = [
":gcd_single_flow_{}_test".format(stage)
for stage in SINGLE_FLOW_STAGES
],
)
11 changes: 11 additions & 0 deletions flow/designs/asap7/gcd/single_flow.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Seed this variant's results dir with the yosys synthesis outputs,
# then run the whole flow in this single OpenROAD process. Under
# bazel-orfs the synthesis results are staged in the src stage's
# variant folder and its odb is exposed via ODB_FILE, while RESULTS_DIR
# points at this run's own variant folder.
file mkdir $::env(RESULTS_DIR)
set src_results [file dirname $::env(ODB_FILE)]
file copy -force $src_results/1_2_yosys.v $::env(RESULTS_DIR)/1_2_yosys.v
file copy -force $src_results/1_2_yosys.sdc $::env(RESULTS_DIR)/1_2_yosys.sdc

source $::env(SCRIPTS_DIR)/flow.tcl
2 changes: 1 addition & 1 deletion flow/scripts/density_fill.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if { $::env(USE_FILL) } {
write_verilog $::env(RESULTS_DIR)/6_1_fill.v
orfs_write_db $::env(RESULTS_DIR)/6_1_fill.odb
} else {
log_cmd exec cp $::env(RESULTS_DIR)/5_route.odb $::env(RESULTS_DIR)/6_1_fill.odb
orfs_copy_db $::env(RESULTS_DIR)/5_route.odb $::env(RESULTS_DIR)/6_1_fill.odb
# There is no 5_route.v file to copy
}

Expand Down
Loading