Skip to content

Commit 88848d4

Browse files
committed
bazel: add //:yosys-check wrapper
Yosys is sensitive to its build environment (abc version, cxxopts version, compile flags), so bazel-built yosys and make-built yosys produce different `1_2_yosys.v` for the same RTL. Different netlists then push QoR metrics around enough to break rules-base.json thresholds even when OpenROAD is bit-deterministic in both flows. We don't care about yosys environmental noise; we care about OpenROAD determinism given the same netlist. `//:yosys-check //flow/designs/<plat>/<design>:<n>_test` feeds bazel's `1_2_yosys.v` into a fresh make-flow run via the existing SYNTH_NETLIST_FILES hook in flow/scripts/synth_preamble.tcl (in production use by flow/designs/gf12/{ca53,bp_dual,bp_quad}), then SHA-compares every stage's .odb between bazel and make. All MATCH -> yosys-only false positive, ignore. Any DIFFER -> real bazel-vs-make OpenROAD divergence to investigate. Resolves the bazel results-subdir (DESIGN_NAME) and make results-subdir (DESIGN_NICKNAME) independently — these differ for aes-block (DESIGN_NAME=aes_cipher_top vs DESIGN_NICKNAME=aes-block) and that mismatch had blocked yosys-check from running on it. Manually verified on asap7/uart (a bazel _test failure with detailedroute__route__wirelength 6.7% over threshold): all 7 stages SHA-match, confirming the failure is yosys-environment noise rather than an OpenROAD divergence. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
1 parent 54c4857 commit 88848d4

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,12 @@ sh_binary(
44
name = "install_for_bazel",
55
srcs = ["bazel/install.sh"],
66
)
7+
8+
# Test whether a failing bazel `_test` is a yosys-environment false
9+
# positive vs a real bazel-vs-make OpenROAD divergence. See
10+
# flow/README.md for the workflow. Usage:
11+
# bazelisk run //:yosys-check //flow/designs/asap7/uart:uart_test
12+
sh_binary(
13+
name = "yosys-check",
14+
srcs = ["bazel/yosys-check.sh"],
15+
)

bazel/yosys-check.sh

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Test whether a failing bazel `_test` is a yosys-environment false
4+
# positive or a real bazel-vs-make OpenROAD divergence.
5+
#
6+
# Usage: bazelisk run //:yosys-check //flow/designs/<plat>/<design>:<n>_test
7+
#
8+
# Yosys is sensitive to its build environment (abc version, cxxopts
9+
# version, compile flags), so bazel-built yosys and make-built yosys
10+
# produce different `1_2_yosys.v` for the same RTL. Different netlists
11+
# then push QoR metrics around enough to break rules-base.json
12+
# thresholds even when OpenROAD is behaving identically. This wrapper
13+
# feeds bazel's pre-built netlist into a fresh make-flow run (via
14+
# SYNTH_NETLIST_FILES) and SHA-compares .odb at every stage:
15+
#
16+
# all MATCH -> yosys-only false positive, ignore.
17+
# any DIFFER -> real bazel-vs-make OpenROAD divergence, investigate.
18+
19+
set -e -u -o pipefail
20+
21+
if [[ $# -ne 1 ]]; then
22+
echo "usage: bazelisk run //:yosys-check <test-label>" >&2
23+
echo " e.g. bazelisk run //:yosys-check //flow/designs/asap7/uart:uart_test" >&2
24+
exit 2
25+
fi
26+
27+
cd "${BUILD_WORKSPACE_DIRECTORY:?must be invoked via bazelisk run}"
28+
29+
LABEL="$1"
30+
31+
# Parse //flow/designs/<plat>/<design>:<name>_test
32+
case "$LABEL" in
33+
//flow/designs/*/*:*_test) ;;
34+
*)
35+
echo "yosys-check: expected //flow/designs/<plat>/<design>:<name>_test, got $LABEL" >&2
36+
exit 2
37+
;;
38+
esac
39+
40+
PKG="${LABEL#//}"; PKG="${PKG%:*}" # flow/designs/asap7/uart
41+
NAME="${LABEL##*:}" # uart_test
42+
DESIGN_DIR="${PKG#flow/designs/}" # asap7/uart
43+
PLAT="${DESIGN_DIR%%/*}" # asap7
44+
DESIGN="${DESIGN_DIR#*/}" # uart
45+
SYNTH_TARGET="//$PKG:${NAME%_test}_synth"
46+
47+
# bazel-orfs and classic make disagree on which design-config var to
48+
# put in the results path: bazel uses DESIGN_NAME (the module/top),
49+
# make uses DESIGN_NICKNAME (the user-friendly tag). For most designs
50+
# they're equal; aes-block is the canonical exception
51+
# (DESIGN_NAME=aes_cipher_top vs DESIGN_NICKNAME=aes-block).
52+
echo "==> Building $SYNTH_TARGET (need bazel's 1_2_yosys.v and the results subdir)"
53+
SYNTH_TARGET="//$PKG:${NAME%_test}_synth"
54+
bazelisk build "$SYNTH_TARGET"
55+
56+
# Bazel side: glob the single subdir under bazel-bin/<pkg>/results/<plat>/.
57+
BAZEL_PLAT_DIR="bazel-bin/$PKG/results/$PLAT"
58+
BAZEL_NICK=$(basename "$(ls -d "$BAZEL_PLAT_DIR"/*/ 2>/dev/null | head -1)" 2>/dev/null)
59+
BAZEL_NICK="${BAZEL_NICK:-$DESIGN}"
60+
61+
# Make side: parse DESIGN_NICKNAME out of the design's config.mk.
62+
MAKE_NICK=$(awk '
63+
/^[[:space:]]*export[[:space:]]+DESIGN_NICKNAME[[:space:]]*=/ {
64+
n = index($0, "="); v = substr($0, n + 1)
65+
gsub(/^[[:space:]]+|[[:space:]]+$/, "", v); print v; exit
66+
}
67+
' "flow/designs/$PLAT/$DESIGN/config.mk")
68+
MAKE_NICK="${MAKE_NICK:-$DESIGN}"
69+
echo "==> bazel subdir=$BAZEL_NICK make subdir=$MAKE_NICK"
70+
71+
BAZEL_RES="bazel-bin/$PKG/results/$PLAT/$BAZEL_NICK/base"
72+
MAKE_RES="flow/results/$PLAT/$MAKE_NICK/base"
73+
74+
echo "==> Building $LABEL (so we have bazel's downstream .odb to compare)"
75+
bazelisk build "$LABEL"
76+
77+
echo "==> Installing OpenROAD into tools/install/ (idempotent)"
78+
( cd tools/OpenROAD && bazelisk run //:install )
79+
80+
BAZEL_NETLIST_RO="$(pwd)/$BAZEL_RES/1_2_yosys.v"
81+
if [[ ! -f "$BAZEL_NETLIST_RO" ]]; then
82+
echo "yosys-check: bazel netlist not at $BAZEL_NETLIST_RO" >&2
83+
exit 1
84+
fi
85+
86+
# synth_preamble.tcl copies SYNTH_NETLIST_FILES with `cp -p`, which
87+
# carries over the source's perms. bazel-out files are read-only, so
88+
# the second copy (do-yosys after do-yosys-canonicalize) hits
89+
# "Permission denied" on the read-only destination. Stage the netlist
90+
# in a writable temp path so both copies succeed.
91+
BAZEL_NETLIST="$(mktemp --suffix=-1_2_yosys.v)"
92+
trap 'rm -f "$BAZEL_NETLIST"' EXIT
93+
cp --no-preserve=mode "$BAZEL_NETLIST_RO" "$BAZEL_NETLIST"
94+
95+
echo "==> make clean_all + metadata with bazel netlist (SYNTH_NETLIST_FILES)"
96+
# Run make in a subshell that tolerates non-zero exit codes — metadata-check
97+
# may fail on QoR thresholds even when the .odb stages are bit-identical to
98+
# bazel. We only care about SHA equivalence; the QoR comparison is bazel's
99+
# `_test` job, and the whole point of yosys-check is to look past that.
100+
( cd flow \
101+
&& make clean_all DESIGN_CONFIG="designs/$PLAT/$DESIGN/config.mk" ) || true
102+
( cd flow \
103+
&& make metadata DESIGN_CONFIG="designs/$PLAT/$DESIGN/config.mk" \
104+
SYNTH_NETLIST_FILES="$BAZEL_NETLIST" ) || true
105+
106+
echo ""
107+
echo "==> .odb SHA matrix (bazel vs make, same netlist)"
108+
printf '%-22s %-18s %-18s %s\n' stage bazel make outcome
109+
all_match=1
110+
for f in 1_synth.odb 2_floorplan.odb 3_place.odb 4_cts.odb \
111+
5_1_grt.odb 5_route.odb 6_final.odb; do
112+
bs=$(sha256sum "$BAZEL_RES/$f" 2>/dev/null | cut -c1-16 || true)
113+
ms=$(sha256sum "$MAKE_RES/$f" 2>/dev/null | cut -c1-16 || true)
114+
if [[ -n "$bs" && "$bs" == "$ms" ]]; then
115+
tag=MATCH
116+
elif [[ -z "$bs" && -z "$ms" ]]; then
117+
tag=skip
118+
else
119+
tag=DIFFER
120+
all_match=0
121+
fi
122+
printf '%-22s %-18s %-18s %s\n' "$f" "${bs:--}" "${ms:--}" "$tag"
123+
done
124+
125+
echo ""
126+
if [[ $all_match -eq 1 ]]; then
127+
echo "yosys-check: all stages MATCH -> bazel _test failure (if any) is a"
128+
echo " yosys-environment false positive; OpenROAD is deterministic."
129+
exit 0
130+
else
131+
echo "yosys-check: some stages DIFFER -> bazel-vs-make OpenROAD divergence."
132+
echo " Investigate compile flags, abc version, etc."
133+
exit 1
134+
fi

0 commit comments

Comments
 (0)