Skip to content
Closed
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
12 changes: 12 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,21 @@ BAZEL_ORFS_COMMIT = "6ebadeb4be5c9ada103081c9a5e668c014126616"
BAZEL_ORFS_REMOTE = "https://github.com/The-OpenROAD-Project/bazel-orfs.git"

# To bump version, run: bazelisk run @bazel-orfs//:bump
#
# The patches carry OpenROAD-SYN support (SYNTH_USE_SYN engine selection,
# synthesis-only metadata/test chain, orfs_design extension hook) until
# they are upstreamed; see patches/bazel-orfs/BUILD.bazel.
git_override(
module_name = "bazel-orfs",
commit = BAZEL_ORFS_COMMIT,
patch_strip = 1,
patches = [
"//patches/bazel-orfs:0001-synth-support-OpenROAD-SYN-engine-SYNTH_USE_SYN-1-an.patch",
"//patches/bazel-orfs:0002-flow-emit-metadata-test-update-chain-for-synthesis-o.patch",
"//patches/bazel-orfs:0003-update-copy-only-rules.json-in-the-orfs_update-scrip.patch",
"//patches/bazel-orfs:0004-design-caller-extension-hook-for-per-design-status-t.patch",
"//patches/bazel-orfs:0005-flow-synthesis-only-QoR-checks-the-synth-subset-of-t.patch",
],
remote = BAZEL_ORFS_REMOTE,
)

Expand Down
3 changes: 3 additions & 0 deletions docs/user/FlowVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ configuration file.
| <a name="SYNTH_INSBUF"></a>SYNTH_INSBUF| Insert input buffers on top-level input ports during synthesis. Useful to disable when doing parallel synthesis and concatenating netlists later as we're generating netlists of submodules.| 1|
| <a name="SYNTH_KEEP_MOCKED_MEMORIES"></a>SYNTH_KEEP_MOCKED_MEMORIES| When `SYNTH_MOCK_LARGE_MEMORIES=1`, setting this to 1, will keep mocked memories (not flattening them). This preserves some of the access logic complexity and avoids optimizations outside of the mocked memory.| 1|
| <a name="SYNTH_KEEP_MODULES"></a>SYNTH_KEEP_MODULES| Mark modules to keep from getting removed in flattening.| |
| <a name="SYNTH_LEC_CHECK"></a>SYNTH_LEC_CHECK| Run a formal equivalence check between the input RTL and the OpenROAD-SYN synthesis netlist (1_synth.v). The RTL side goes through kepler-formal's experimental SystemVerilog frontend, which does not yet support all RTL constructs, so this is a separate opt-in from LEC_CHECK (which auto-enables when kepler-formal is installed and compares gate-level netlists only). Requires KEPLER_FORMAL_EXE.| 0|
| <a name="SYNTH_MEMORY_MAX_BITS"></a>SYNTH_MEMORY_MAX_BITS| Maximum number of bits for memory synthesis. Ideally, real RAM or realistic fakeram should be used for RAMs much larger than 1024 bits. To temporarily ignore the RAM concerns and investigate other aspects of the design, consider setting `SYNTH_MOCK_LARGE_MEMORIES=1`, or adjusting `SYNTH_MEMORY_MAX_BITS`.| 4096|
| <a name="SYNTH_MINIMUM_KEEP_SIZE"></a>SYNTH_MINIMUM_KEEP_SIZE| For hierarchical synthesis, we keep modules of larger area than given by this variable and flatten smaller modules. The area unit used is the size of a basic nand2 gate from the platform's standard cell library. The default value is platform specific.| 0|
| <a name="SYNTH_MOCK_LARGE_MEMORIES"></a>SYNTH_MOCK_LARGE_MEMORIES| Reduce Yosys inferred memories larger than SYNTH_MEMORY_MAX_BITS to 1 row. Yosys will generally infer memories from behavioral Verilog code, whether the memories are in standalone modules or instantiated within some larger module. fakeram and empty Verilog memories(blackboxes) of memories will not be inferred memories by Yosys and are therefore not affected by this variable. This is useful and convenient to separate the concern of instantiating and placing memories from investigating other issues with a design, though it comes at the expense of the increased accuracy that using realistic fakemem would provide. Memories with a single 1 row will of course have unrealistically good timing and area characteristics, but timing will still correctly terminate in a register. Large port memories, typically register files, will still have the retain a lot of the port logic that can be useful to investigate issues. This can be especially useful during development of designs where the behavioral model comes first and suitable memories are matched up when the design RTL is stable. A typical use case would be Chisel which will generate a behavioral model for a memories with the required clocks, ports, etc. in addition to a computer readable file with the specification of the memories that is used to [automatically](https://chipyard.readthedocs.io/en/stable/Tools/Barstools.html/) match up suitable memory macros later in the flow. During an architectural screening study, a large range of memory configurations can be investigated quickly with this option, without getting bogged down in the concern of how to realize the memories in silicon for emphemral RTL configurations that exist only long enough to run through the ORFS flow to create a table of some characteristics of a design configuration.| 0|
Expand Down Expand Up @@ -345,6 +346,7 @@ configuration file.
- [DFF_LIB_FILE](#DFF_LIB_FILE)
- [DFF_MAP_FILE](#DFF_MAP_FILE)
- [LATCH_MAP_FILE](#LATCH_MAP_FILE)
- [LEC_AUX_VERILOG_FILES](#LEC_AUX_VERILOG_FILES)
- [MIN_BUF_CELL_AND_PORTS](#MIN_BUF_CELL_AND_PORTS)
- [POST_SYNTH_TCL](#POST_SYNTH_TCL)
- [PRE_SYNTH_TCL](#PRE_SYNTH_TCL)
Expand All @@ -362,6 +364,7 @@ configuration file.
- [SYNTH_INSBUF](#SYNTH_INSBUF)
- [SYNTH_KEEP_MOCKED_MEMORIES](#SYNTH_KEEP_MOCKED_MEMORIES)
- [SYNTH_KEEP_MODULES](#SYNTH_KEEP_MODULES)
- [SYNTH_LEC_CHECK](#SYNTH_LEC_CHECK)
- [SYNTH_MEMORY_MAX_BITS](#SYNTH_MEMORY_MAX_BITS)
- [SYNTH_MINIMUM_KEEP_SIZE](#SYNTH_MINIMUM_KEEP_SIZE)
- [SYNTH_MOCK_LARGE_MEMORIES](#SYNTH_MOCK_LARGE_MEMORIES)
Expand Down
186 changes: 186 additions & 0 deletions flow/designs/asap7/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# OpenROAD-SYN status suite for asap7.
#
# Every asap7 design gets manual <name>_syn_* targets from the config.mk
# DSL (see flow/designs/design.bzl): a synthesis-only variant "syn" flow
# with SYNTH_USE_SYN=1 forced, a QoR gate checking the synthesis-stage
# subset of the design's rules-base.json (no per-variant rules files in
# git), and a best-effort <name>_syn_qor / <name>_yosys_qor pair for the
# comparison graph. This package aggregates them:
#
# bazelisk test //flow/designs/asap7:syn_test
# bazelisk build //flow/designs/asap7:syn_qor_png
#
# The suite deliberately includes designs that fail OpenROAD-SYN today —
# it is a status report, not a green-only gate. A design can fail by not
# synthesizing at all, or by missing the rules-base.json gates that its
# regular flow meets (e.g. aes-block's SYN area blows past the yosys
# reference).

# Design directory -> DESIGN_NAME (bazel target prefix), ordered
# fastest-first so --keep_going runs surface quick failures early.
# Expected failures / quirks are listed last. "minimal" is excluded: it
# has no VERILOG_FILES and thus no generated design targets.
SYN_TEST_DESIGNS = {
"gcd": "gcd", # smoketest, fast
"uart": "uart",
"mock-alu": "MockAlu",
"riscv32i": "riscv_top",
"aes": "aes_cipher_top",
"aes_lvt": "aes_cipher_top",
"aes-mbff": "aes_cipher_top",
"jpeg": "jpeg_encoder",
"jpeg_lvt": "jpeg_encoder",
"ethmac": "ethmac",
"ethmac_lvt": "ethmac",
"mock-cpu": "mock_cpu",
"gcd-ccs": "gcd", # CCS liberty
"aes-block": "aes_cipher_top", # hierarchical BLOCKS
}

# Designs whose OpenROAD-SYN run is too slow (or does not terminate) for
# the aggregators. Their generated per-design targets stay tags=["manual"]
# like all syn targets, but they are deliberately left out of syn_test and
# the QoR graph so those remain runnable; reproduce individually, e.g.
# bazelisk build //flow/designs/asap7/ibex:ibex_core_syn_synth
#
# - ibex: sv_elaborate/synthesize/repair_design complete in seconds, but
# report_metrics ("Report metrics stage 1, synth...") spins in STA for
# hours (observed >2h on 48 threads with no progress).
# - cva6: synthesize itself takes ~73s, but repair_design -pre_placement
# was still running after 10+ minutes when the status sweep was cut
# off; not yet characterized to completion.
# - swerv_wrapper: largest design in the suite; not yet run to
# completion under OpenROAD-SYN in this environment.
# - riscv32i-mock-sram: hierarchical BLOCKS (fakeram) — the syn variant
# first needs the block's full PnR flow for its abstract; not yet run
# to completion.
SYN_SLOW_DESIGNS = {
"cva6": "cva6",
"ibex": "ibex_core",
"riscv32i-mock-sram": "riscv_top",
"swerv_wrapper": "swerv_wrapper",
}

# Designs whose OpenROAD-SYN synthesis fails today. They stay in
# syn_test (failing honestly) and in the QoR graph (best-effort FAIL
# columns), but the clock-period plot depends on each design's generated
# synthesis rules snapshot, which these cannot produce.
# - mock-alu: SDC references yosys-style register names (*io_out_REG*)
# absent from the SYN netlist.
# - riscv32i: slang rejects procedural assignment to nets (dmem.v).
# - mock-cpu: slang rejects endianness-mismatched part-select
# (wptr_full.v).
SYN_FAILING_DESIGNS = [
"mock-alu",
"mock-cpu",
"riscv32i",
]

# Generated synthesis QoR snapshots (rules.json from the syn variant's
# update_rules stage) for designs whose OpenROAD-SYN synthesis passes.
# These are bazel outputs, not checked-in files: the syn variant's QoR
# gate checks the synthesis subset of rules-base.json instead, so no
# rules-syn.json files live in git.
[
filegroup(
name = "{pkg}_syn_rules".format(pkg = pkg),
srcs = [
"//flow/designs/asap7/{pkg}:{name}_syn_update_rules".format(
name = name,
pkg = pkg,
),
],
output_group = "rules.json",
)
for pkg, name in SYN_TEST_DESIGNS.items()
if pkg not in SYN_FAILING_DESIGNS
]

# Explicitly listed manual tests DO run through a test_suite (the manual
# tag only exempts them from wildcard expansion); the suite itself is
# manual so `bazelisk test //flow/...` does not pull them in either.
test_suite(
name = "syn_test",
tags = ["manual"],
tests = [
"//flow/designs/asap7/{pkg}:{name}_syn_test".format(
name = name,
pkg = pkg,
)
for pkg, name in SYN_TEST_DESIGNS.items()
],
)

# The syn-vs-yosys QoR comparison graph plus the runtime A/B chart. A
# plain build target: the per-design _qor inputs are best-effort (marker
# JSON on failure), so this always builds and failing designs render as
# hatched FAIL columns.
#
# Refresh the checked-in copies embedded by the status PR with:
# bazelisk build //flow/designs/asap7:syn_qor_png
# cp -f bazel-bin/flow/designs/asap7/openroad-syn-{qor,runtime}.png \
# flow/docs/images/
# Effective clock period (target - gated worst slack) across stages,
# one series per design, OpenROAD-SYN synthesis point overlaid. The base
# series comes from the checked-in rules-base.json; the SYN point comes
# from the generated synthesis rules snapshot (the syn variant's
# update_rules output), so building this runs synthesis for the passing
# designs. Same refresh pattern as syn_qor_png, into
# flow/docs/images/openroad-syn-clock-period.png.
genrule(
name = "clock_period_png",
srcs = [
"//flow/designs/asap7/{pkg}:rules-base.json".format(pkg = pkg)
for pkg in SYN_TEST_DESIGNS
if pkg not in SYN_FAILING_DESIGNS
] + [
":{pkg}_syn_rules".format(pkg = pkg)
for pkg in SYN_TEST_DESIGNS
if pkg not in SYN_FAILING_DESIGNS
],
outs = ["openroad-syn-clock-period.png"],
cmd = "$(location //flow/util:plotClockPeriod) --output $@ " + " ".join([
("--design {pkg} " +
"--rules-base $(location //flow/designs/asap7/{pkg}:rules-base.json) " +
"--rules-syn $(location :{pkg}_syn_rules)").format(
pkg = pkg,
)
for pkg in SYN_TEST_DESIGNS
if pkg not in SYN_FAILING_DESIGNS
]),
tags = ["manual"],
tools = ["//flow/util:plotClockPeriod"],
)

genrule(
name = "syn_qor_png",
srcs = [
"//flow/designs/asap7/{pkg}:{name}_{kind}_qor".format(
name = name,
kind = kind,
pkg = pkg,
)
for pkg, name in SYN_TEST_DESIGNS.items()
for kind in [
"syn",
"yosys",
]
],
outs = [
"openroad-syn-qor.png",
"openroad-syn-runtime.png",
],
cmd = "$(location //flow/util:plotSynQoR) " +
"--output $(location openroad-syn-qor.png) " +
"--runtime-output $(location openroad-syn-runtime.png) " + " ".join([
("--design {pkg} " +
"--syn $(location //flow/designs/asap7/{pkg}:{name}_syn_qor) " +
"--base $(location //flow/designs/asap7/{pkg}:{name}_yosys_qor)").format(
name = name,
pkg = pkg,
)
for pkg, name in SYN_TEST_DESIGNS.items()
]),
tags = ["manual"],
tools = ["//flow/util:plotSynQoR"],
)
34 changes: 25 additions & 9 deletions flow/designs/asap7/gcd/BUILD
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
load("@bazel-orfs//:openroad.bzl", "orfs_run")
load("@bazel-orfs//:openroad.bzl", "orfs_flow", "orfs_run")
load("@orfs_designs//:designs.bzl", "DESIGNS")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//flow/designs:design.bzl", "design")

# 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"],
)

# gcd's regular flow follows config.mk onto OpenROAD-SYN
# (SYNTH_USE_SYN=1), but the single-process comparison below
# deliberately exercises the yosys netlist path (single_flow.tcl seeds
# from 1_2_yosys.v). Give the comparison its own yosys-engine flow;
# manual so only the gcd_single_flow_test suite builds it.
orfs_flow(
name = "gcd",
arguments = {
k: v
for k, v in DESIGNS["asap7/gcd"]["arguments"].items()
if k != "SYNTH_USE_SYN"
},
pdk = "//flow:asap7",
sources = DESIGNS["asap7/gcd"]["sources"],
tags = ["manual"],
variant = "yosys",
verilog_files = DESIGNS["asap7/gcd"]["verilog_files"],
)

# Stage-boundary .odb/.sdc stems shared by the normal per-stage flow
Expand Down Expand Up @@ -56,7 +70,7 @@ SINGLE_FLOW_EXTRA_OUTS = [
# this package.
orfs_run(
name = "gcd_single_flow",
src = ":gcd_synth",
src = ":gcd_yosys_synth",
outs = [
"results/asap7/gcd/single/{}.{}".format(stem, ext)
for stem in SINGLE_FLOW_STAGES.values()
Expand All @@ -79,11 +93,13 @@ orfs_run(
variant = "single",
)

# Normal-flow stage outputs, one filegroup per compared file.
# Normal-flow stage outputs, one filegroup per compared file. Taken from
# the yosys-engine variant above so both sides of the byte-compare start
# from the same yosys netlist.
[
filegroup(
name = "gcd_base_{}_{}".format(stage, ext),
srcs = [":gcd_" + stage],
srcs = [":gcd_yosys_" + stage],
output_group = "{}.{}".format(stem, ext),
)
for stage, stem in SINGLE_FLOW_STAGES.items()
Expand Down
75 changes: 74 additions & 1 deletion flow/designs/design.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""BUILD boilerplate for flow/designs/."""

load("@bazel-orfs//:openroad.bzl", "orfs_flow")
load("@orfs_designs//:designs.bzl", "orfs_design")
load("//flow/designs:qor.bzl", "orfs_qor")

# Per filegroup target: extensions included in the filegroup.
# bazel-orfs's config_mk_parser produces these target names from
Expand All @@ -17,7 +19,9 @@ _GROUPS = {
# cross-package references resolve. Kept tight on purpose: globbing "*"
# silently exposes LICENSE/.gitignore/etc. as the public API surface.
# gds/gds.gz are inputs in hierarchical flows via ADDITIONAL_GDS.
_EXPORTED_EXTS = ["v", "sv", "svh", "tcl", "sdc", "def", "cfg", "lef", "lib", "gds", "gds.gz"]
# json covers rules-*.json so QoR reporting targets (e.g.
# //flow/designs/asap7:clock_period_png) can consume them per file.
_EXPORTED_EXTS = ["v", "sv", "svh", "tcl", "sdc", "def", "cfg", "lef", "lib", "gds", "gds.gz", "json"]

_EXPORTS_SENTINEL = "_orfs_design_exports_sentinel"

Expand Down Expand Up @@ -51,6 +55,74 @@ def _export_design_files():
visibility = ["//visibility:private"],
)

def _syn_status_targets(
name,
platform,
verilog_files,
arguments,
user_arguments,
sources,
user_sources,
macros,
stage_data,
tags): # buildifier: disable=unused-variable
"""OpenROAD-SYN status targets for one design (orfs_design extra hook).

Emits, always tagged "manual" (even for CI designs, so only explicit
invocations such as //flow/designs/asap7:syn_test run them):

- a synthesis-only variant "syn" flow with SYNTH_USE_SYN=1 forced,
regardless of the config.mk default: <name>_syn_synth plus — when
the design has a rules-base.json — the <name>_syn_test QoR gate
(checking the synthesis-stage subset of rules-base.json, so no
per-variant rules file is committed) and <name>_syn_update_rules,
whose generated rules.json is the synthesis QoR snapshot that
aggregating plots consume.
- a best-effort <name>_syn_qor / <name>_yosys_qor pair whose
qor.json outputs feed the syn-vs-yosys QoR comparison graph.
"""
qor_sources = {k: v for k, v in sources.items() if k != "RULES_JSON"}
orfs_flow(
name = name,
verilog_files = verilog_files,
pdk = "//flow:" + platform,
arguments = arguments | {"SYNTH_USE_SYN": "1"},
user_arguments = user_arguments,
# sources carries the auto-detected rules-base.json as RULES_JSON;
# the syn variant's test checks its synthesis-stage subset.
sources = sources,
user_sources = user_sources,
macros = macros,
stage_data = stage_data,
variant = "syn",
last_stage = "synth",
tags = ["manual"],
test_kwargs = {"tags": ["manual"]},
# The platform-level aggregation package consumes the
# update_rules stage's generated rules.json.
visibility = ["//visibility:public"],
)
for qor_variant, qor_use_syn in [("syn_qor", True), ("yosys_qor", False)]:
orfs_qor(
name = "%s_%s" % (name, qor_variant),
use_syn = qor_use_syn,
module_top = name,
variant = qor_variant,
verilog_files = verilog_files,
pdk = "//flow:" + platform,
# user_arguments are dropped by the synth-stage argument
# filter; designs whose synthesis depends on user .tcl hooks
# may fail their best-effort QoR run and render as FAILED.
arguments = arguments,
sources = qor_sources,
deps = macros,
stage_data = stage_data,
tags = ["manual"],
# Consumed by the platform-level aggregation package (e.g.
# //flow/designs/asap7:syn_qor_png).
visibility = ["//visibility:public"],
)
Comment thread
oharboe marked this conversation as resolved.

def design(config = "config.mk", user_arguments = [], user_sources = [], local_arguments = []):
"""Standard BUILD body for flow/designs/<platform>/<design>/.

Expand All @@ -75,6 +147,7 @@ def design(config = "config.mk", user_arguments = [], user_sources = [], local_a
user_sources = user_sources,
local_arguments = local_arguments,
blender = True,
extra = _syn_status_targets,
)

def files(group, extra_srcs = None):
Expand Down
Loading