Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -1,3 +1,12 @@
build --incompatible_strict_action_env
build --cxxopt "-std=c++20" --host_cxxopt "-std=c++20"

# 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
# lockfile just means every bazel-orfs / yosys / openroad bump produces
# a 1000-line lock diff that buries the real change. Matches what
# bazel-orfs itself does (its own .bazelrc:7).
common --lockfile_mode=off

try-import %workspace%/user.bazelrc
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ bazel-bin
bazel-out
bazel-OpenROAD-flow-scripts
bazel-testlogs
MODULE.bazel.lock

# python venv
venv/
Expand Down
17 changes: 14 additions & 3 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ bazel_dep(name = "rules_shell", version = "0.6.1")
# time.

bazel_dep(name = "toolchains_llvm", version = "1.5.0", dev_dependency = True)

bazel_dep(name = "openroad", dev_dependency = True)
local_path_override(
module_name = "openroad",
Expand All @@ -37,14 +36,23 @@ git_override(
bazel_dep(name = "bazel-orfs", dev_dependency = True)
bazel_dep(name = "bazel-orfs-verilog", dev_dependency = True)

BAZEL_ORFS_COMMIT = "717655415dd4446ca4e2fc09907465c75cb23912"
BAZEL_ORFS_COMMIT = "ce6efd96dfe39a9c4ef244f8712386f071545d77"

BAZEL_ORFS_REMOTE = "https://github.com/The-OpenROAD-Project/bazel-orfs.git"

# To bump version, run: bazelisk run @bazel-orfs//:bump
git_override(
module_name = "bazel-orfs",
commit = BAZEL_ORFS_COMMIT,
patch_strip = 1,
patches = [
# Adds orfs_design(user_sources=[VAR,...]) / orfs_flow(user_sources={...})
# so design-private SOURCE_VARS path hooks (e.g. SDC_FILE_EXTRA in
# flow/designs/asap7/mock-cpu) bypass the variables.yaml validator
# without polluting the ORFS-wide variable schema. Drop once upstream
# bazel-orfs lands the user_sources= API.
"//bazel:0001-orfs_design-add-user_sources.patch",
],
remote = BAZEL_ORFS_REMOTE,
)

Expand Down Expand Up @@ -79,7 +87,10 @@ llvm.toolchain(
)
use_repo(llvm, "llvm_toolchain")

register_toolchains("@llvm_toolchain//:all", dev_dependency = True)
register_toolchains(
"@llvm_toolchain//:all",
dev_dependency = True,
)

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
Expand Down
5,190 changes: 0 additions & 5,190 deletions MODULE.bazel.lock

This file was deleted.

153 changes: 153 additions & 0 deletions bazel/0001-orfs_design-add-user_sources.patch
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this for? It seems to relate to private files not in ORFS.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It will wash out in the next bump, already merged in bazel-orfs. I patch things here to check if they work out to reduce churn in bazel-orfs as the use-case originated here.

Patching to reduce churn and let the use-case settle and then upstreaming is idiomatic for bazel usage.

Any other comments?

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
From 58df356479d6d9f04aa0bc3ac3676d3b89d26813 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=98yvind=20Harboe?= <oyvind@ascenium.com>
Date: Thu, 14 May 2026 18:48:12 +0200
Subject: [PATCH] orfs_design/orfs_flow: add user_sources= for design-private
path hooks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Symmetric to user_arguments=, but for source-typed (path-label) vars:
a variable that the config_mk_parser classifies as a SOURCE_VAR (path
staged into the sandbox via _map_source_file) but that is read only
by user-supplied .tcl/.mk and has no entry in ORFS variables.yaml.

Today such a variable bumps into check_variables(sources.keys()) in
orfs_flow and fails the load phase, even though the file itself is
staged correctly. user_arguments= doesn't help because it pops from
arguments, not sources.

The motivating case is SDC_FILE_EXTRA — set by
flow/designs/asap7/mock-cpu/config.mk and source'd from that design's
io.tcl, with no ORFS-side consumer. SDC_FILE_EXTRA is in this file's
SOURCE_VARS list, so its value is path-staged; making it work without
declaring it as a global ORFS variable is what user_sources= is for.

API:
- orfs_design() gains user_sources=[VAR, ...]. Each named var is
popped from sources and forwarded as orfs_flow(user_sources={...}).
- orfs_flow() gains user_sources={VAR: [label, ...]}. Merged into
sources before _orfs_pass so files are still staged, but the key
set skips check_variables. Same shadowing guard as user_arguments=:
collision with a known ORFS variable fails fast.

Mirrors user_arguments= in both surface and intent.

Signed-off-by: Øyvind Harboe <oyvind@ascenium.com>
---
private/flow.bzl | 19 +++++++++++++++++--
private/orfs_design.bzl | 19 ++++++++++++++++++-
2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/private/flow.bzl b/private/flow.bzl
index fd9001f..b59d059 100644
--- a/private/flow.bzl
+++ b/private/flow.bzl
@@ -171,6 +171,7 @@ def orfs_flow(
verilog_files = [],
macros = [],
sources = {},
+ user_sources = {},
stage_sources = {},
stage_arguments = {},
renamed_inputs = {},
@@ -213,6 +214,12 @@ def orfs_flow(
validating against ORFS variables.yaml. Use for vars read only by user-supplied .tcl/.mk
(e.g. ARRAY_COLS in a project's MACRO_PLACEMENT_TCL). Keys that collide with known ORFS
variables are rejected — route those through 'arguments' instead.
+ user_sources: dictionary of project-specific source-typed (path-label) env vars to expose
+ to every stage without validating against ORFS variables.yaml. The path is still staged
+ into the sandbox like a normal source — only the variable name skips the validator.
+ Use for path hooks read only by user-supplied .tcl/.mk (e.g. an extra-SDC hook
+ source'd from the design's own io.tcl). Keys that collide with known ORFS variables
+ are rejected — route those through 'sources' instead.
extra_arguments: dictionary keyed by ORFS stages with lists of .json argument file labels.
These .json files are merged into the stage config, providing computed arguments
that flow through OrfsInfo to subsequent stages.
@@ -269,6 +276,14 @@ def orfs_flow(
) +
"Use arguments= for ORFS variables; reserve user_arguments= for project-specific env vars.",
)
+ shadowed_srcs = sorted([k for k in user_sources if k in ALL_VARIABLE_TO_STAGES])
+ if shadowed_srcs:
+ fail(
+ "user_sources contains known ORFS variable(s): {shadowed}. ".format(
+ shadowed = ", ".join(shadowed_srcs),
+ ) +
+ "Use sources= for ORFS variables; reserve user_sources= for project-specific path hooks.",
+ )
if abstract_stage and last_stage:
fail("abstract_stage and last_stage are mutually exclusive")
if variant == "base":
@@ -281,7 +296,7 @@ def orfs_flow(
top = top,
verilog_files = verilog_files,
macros = macros,
- sources = sources,
+ sources = sources | user_sources,
stage_sources = stage_sources,
stage_arguments = stage_arguments,
renamed_inputs = renamed_inputs,
@@ -319,7 +334,7 @@ def orfs_flow(
top = top,
verilog_files = verilog_files,
macros = macros,
- sources = sources,
+ sources = sources | user_sources,
stage_sources = stage_sources,
stage_arguments = stage_arguments,
renamed_inputs = {},
diff --git a/private/orfs_design.bzl b/private/orfs_design.bzl
index 554da44..d53d4bd 100644
--- a/private/orfs_design.bzl
+++ b/private/orfs_design.bzl
@@ -47,7 +47,7 @@ def _convert_sources(sources, pkg):
result[var] = converted
return result

-def orfs_design(name = None, config = "config.mk", platform = None, design = None, designs = None, mock_openroad = None, mock_yosys = None, user_arguments = [], local_arguments = []): # buildifier: disable=unused-variable
+def orfs_design(name = None, config = "config.mk", platform = None, design = None, designs = None, mock_openroad = None, mock_yosys = None, user_arguments = [], user_sources = [], local_arguments = []): # buildifier: disable=unused-variable
"""Create orfs_flow() targets for a design based on its parsed config.mk.

Usage:
@@ -79,6 +79,13 @@ def orfs_design(name = None, config = "config.mk", platform = None, design = Non
Routed through orfs_flow(user_arguments=...) to bypass the
variables.yaml validator instead of being checked as known
ORFS arguments.
+ user_sources: List of source-typed variable names (vars in
+ SOURCE_VARS) that are project-specific path hooks read only
+ by user-supplied .tcl/.mk, not by ORFS itself (e.g. a
+ per-design extra-SDC hook source'd from the design's own
+ io.tcl). Routed through orfs_flow(user_sources=...) so the
+ file is still staged into the sandbox, but the variable
+ name bypasses the variables.yaml validator.
local_arguments: List of variable names that are only used for
$(VAR) expansion within the same config.mk and are not read
by ORFS or by any user .tcl/.mk (e.g. VERILOG_FILES_BLACKBOX,
@@ -195,6 +202,15 @@ def orfs_design(name = None, config = "config.mk", platform = None, design = Non
if var in arguments:
user_args[var] = arguments.pop(var)

+ # Same idea for source-typed (path-label) project-specific knobs:
+ # variables that are in SOURCE_VARS (so the parser staged the path
+ # as a label) but are read only by user .tcl/.mk and have no
+ # variables.yaml entry.
+ user_srcs = {}
+ for var in user_sources:
+ if var in sources:
+ user_srcs[var] = sources.pop(var)
+
# Default SYNTH_NUM_PARTITIONS to a static value so that the action graph
# is identical across machines and remote cache hits are possible. Users
# who prefer local parallelism over caching can pass NUM_CPUS explicitly.
@@ -213,6 +229,7 @@ def orfs_design(name = None, config = "config.mk", platform = None, design = Non
arguments = arguments,
user_arguments = user_args,
sources = sources,
+ user_sources = user_srcs,
macros = macros if macros else [],
stage_data = {"synth": extra_data} if extra_data else {},
tags = tags,
--
2.51.0

1 change: 1 addition & 0 deletions bazel/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports_files(glob(["*.patch"]))
4 changes: 4 additions & 0 deletions docs/user/FlowVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ configuration file.
| <a name="LEC_AUX_VERILOG_FILES"></a>LEC_AUX_VERILOG_FILES| Additional Verilog files (e.g. blackbox stubs) to include in LEC equivalence checks. Appended to the generated Verilog netlist before running the formal equivalence check.| |
| <a name="LEC_CHECK"></a>LEC_CHECK| Perform a formal equivalence check between before and after netlists. If this fails, report an issue to OpenROAD.| 0|
| <a name="LIB_FILES"></a>LIB_FILES| A Liberty file of the standard cell library with PVT characterization, input and output characteristics, timing and power definitions for each cell.| |
| <a name="LIB_MODEL"></a>LIB_MODEL| Selects between NLDM and CCS timing models for the ASAP7 platform. Valid values: NLDM (default), CCS. Used in flow/platforms/asap7/config.mk to pick the LIB_DIR subdirectory and accumulate the corresponding $(CORNER)_$(LIB_MODEL)_LIB_FILES list, and in flow/scripts/load.tcl to gate CCS-specific Tcl branches.| NLDM|
| <a name="MACRO_BLOCKAGE_HALO"></a>MACRO_BLOCKAGE_HALO| Distance beyond the edges of a macro that will also be covered by the blockage generated for that macro. Note that the default macro blockage halo comes from the largest of the specified MACRO_PLACE_HALO x or y values. This variable overrides that calculation.| |
| <a name="MACRO_EXTENSION"></a>MACRO_EXTENSION| Sets the number of GCells added to the blockages boundaries from macros.| |
| <a name="MACRO_PLACEMENT_TCL"></a>MACRO_PLACEMENT_TCL| Specifies the path of a TCL file on how to place macros manually. The user may choose to place just some of the macros in the design. The macro placer will handle the remaining unplaced macros.| |
Expand All @@ -188,6 +189,7 @@ configuration file.
| <a name="MAX_REPAIR_TIMING_ITER"></a>MAX_REPAIR_TIMING_ITER| Maximum number of iterations for repair setup and repair hold.| |
| <a name="MAX_ROUTING_LAYER"></a>MAX_ROUTING_LAYER| The highest metal layer name to be used in routing.| |
| <a name="MIN_BUF_CELL_AND_PORTS"></a>MIN_BUF_CELL_AND_PORTS| Used to insert a buffer cell to pass through wires. Used in synthesis.| |
| <a name="MIN_CLK_ROUTING_LAYER"></a>MIN_CLK_ROUTING_LAYER| The lowest metal layer name to be used for clock-net routing in global routing. Used in flow/platforms/*/fastroute.tcl as the lower bound of `set_routing_layers -clock`. Typically higher than MIN_ROUTING_LAYER so clock nets prefer the upper, lower-RC layers. No `stages:` list because floorplan.tcl also `source`s the platform fastroute.tcl.| |
| <a name="MIN_PLACE_STEP_COEF"></a>MIN_PLACE_STEP_COEF| Sets the minimum phi coefficient (pcof_min / µ_k Lower Bound) for global placement optimization. This parameter controls the step size lower bound in the RePlAce Nesterov optimization algorithm. Lower values may improve convergence but can increase runtime. Valid range: 0.95-1.05| 0.95|
| <a name="MIN_ROUTING_LAYER"></a>MIN_ROUTING_LAYER| The lowest metal layer name to be used in routing.| |
| <a name="NUM_CORES"></a>NUM_CORES| Passed to `openroad -threads $(NUM_CORES)`, defaults to numbers of cores in system as determined by system specific code in Makefile, `nproc` is tried first. OpenROAD does not limit itself to this number of cores across OpenROAD running instances, which can lead to overprovisioning in contexts such as bazel-orfs where there could be many routing, or place jobs running at the same time.| |
Expand Down Expand Up @@ -643,7 +645,9 @@ configuration file.
- [KLAYOUT_TECH_FILE](#KLAYOUT_TECH_FILE)
- [LAYER_PARASITICS_FILE](#LAYER_PARASITICS_FILE)
- [LIB_FILES](#LIB_FILES)
- [LIB_MODEL](#LIB_MODEL)
- [MACRO_EXTENSION](#MACRO_EXTENSION)
- [MIN_CLK_ROUTING_LAYER](#MIN_CLK_ROUTING_LAYER)
- [PLATFORM](#PLATFORM)
- [PLATFORM_TCL](#PLATFORM_TCL)
- [PROCESS](#PROCESS)
Expand Down
107 changes: 97 additions & 10 deletions flow/BUILD
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
load("@bazel-orfs//:openroad.bzl", "orfs_pdk")

# Expose every individual file under platforms/ as a public source-file
# target, so designs in other packages can refer to e.g.
# //flow:platforms/asap7/verilog/fakeram7_64x28.sv directly. This is the
# label form bazel-orfs's config_mk_parser produces for VERILOG_FILES /
# ADDITIONAL_LEFS / ADDITIONAL_LIBS that point at platform-provided files.
# Exclude package BUILD files so they aren't claimed as source labels by
# any future sub-package under platforms/.
exports_files(
glob(
["platforms/**/*"],
exclude = [
"platforms/**/BUILD",
"platforms/**/BUILD.bazel",
],
),
visibility = ["//visibility:public"],
)

# files shared between scripts/synth.sh and scripts/flow.sh steps
MAKEFILE_SHARED = [
"scripts/variables.json",
Expand Down Expand Up @@ -47,27 +65,96 @@ filegroup(
pdk = pdk,
)
for ext in {
"asap7": ["cfg", "gds", "lef", "lib", "lib.gz", "lyt", "mk", "rules", "sdc", "sv", "tcl", "v"],
"gf180": ["cfg", "gds", "lef", "lib.gz", "lyt", "mk", "rules", "tcl", "v"],
"ihp-sg13g2": ["gds", "json", "lef", "lib", "lyt", "mk", "rules", "tcl", "v"],
"nangate45": ["cfg", "gds", "lef", "lib", "lyt", "mk", "rules", "tcl", "v"],
"sky130hd": ["gds", "lef", "lib", "lyt", "mk", "rules", "tcl", "tlef", "v"],
"sky130hs": ["gds", "lef", "lib", "lyt", "mk", "rules", "tcl", "tlef", "v"],
"asap7": [
"cfg",
"gds",
"lef",
"lib",
"lib.gz",
"lyt",
"mk",
"rules",
"sdc",
"sv",
"tcl",
"v",
],
"gf180": [
"cfg",
"gds",
"lef",
"lib.gz",
"lyt",
"mk",
"rules",
"tcl",
"v",
],
"ihp-sg13g2": [
"gds",
"json",
"lef",
"lib",
"lyt",
"mk",
"rules",
"tcl",
"v",
],
"nangate45": [
"cfg",
"gds",
"lef",
"lib",
"lyt",
"mk",
"rules",
"tcl",
"v",
],
"sky130hd": [
"gds",
"lef",
"lib",
"lyt",
"mk",
"rules",
"tcl",
"tlef",
"v",
],
"sky130hs": [
"gds",
"lef",
"lib",
"lyt",
"mk",
"rules",
"tcl",
"tlef",
"v",
],
}.get(pdk, [])
] + [
"platforms/common/**/*.v",
]),
config = ":platforms/{pdk}/config.mk".format(pdk = pdk),
libs = glob([
"platforms/{pdk}/**/*.{ext}".format(
pdk = pdk,
ext = ext,
pdk = pdk,
)
for ext in {
"asap7": ["lib", "lib.gz"],
"asap7": [
"lib",
"lib.gz",
],
"gf180": ["lib.gz"],
}.get(pdk, ["lib"])
}.get(
pdk,
["lib"],
)
]),
config = ":platforms/{pdk}/config.mk".format(pdk = pdk),
visibility = ["//visibility:public"],
) for pdk in [
"asap7",
Expand Down
8 changes: 7 additions & 1 deletion flow/designs/asap7/mock-alu/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
load("//flow/designs:design.bzl", "design")

design(config = "config.mk")
design(
config = "config.mk",
user_arguments = [
"MOCK_ALU_OPERATIONS",
"MOCK_ALU_WIDTH",
],
)
Loading