Skip to content

Commit 422c455

Browse files
committed
docs: visualize deterministic RTL regression
1 parent 0859dee commit 422c455

4 files changed

Lines changed: 197 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ jobs:
3030
- name: Test Python golden model
3131
run: python -m unittest discover -s tests -v
3232

33+
- name: Check generated README evidence
34+
run: python tools/render_readme_assets.py --check
35+
3336
- name: Regress single-lane parameter case
3437
run: python tools/run_regression.py --sim iverilog --vec-len 1 --random-cases 40
3538

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ I kept the scope deliberately small: parameterized SystemVerilog, ready/valid
1010
control, a bit-exact Python reference model, deterministic regression, and CI.
1111
This is **not** a trained AI model or a complete neural-network accelerator.
1212

13+
<p align="center">
14+
<img src="assets/rtl-regression.svg" width="100%" alt="Deterministic RTL regression matrix across vector lengths 1, 8, and 17">
15+
</p>
16+
17+
The figure is generated from the checked-in CI matrix. It counts verification
18+
transactions; it is not a throughput, timing, area, power, FPGA, or silicon
19+
benchmark.
20+
1321
## What is implemented
1422

1523
- Synthesizable SystemVerilog with configurable vector length
@@ -72,6 +80,7 @@ lane. See [Architecture](docs/architecture.md) for timing and width details.
7280
| `model/dot_product_model.py` | Bit-exact reference arithmetic and packing |
7381
| `tb/tb_int8_dot_product.sv` | Self-checking ready/valid testbench |
7482
| `tools/run_regression.py` | Vector generation, compile, and simulation harness |
83+
| `tools/render_readme_assets.py` | Rebuilds and checks the README evidence figure |
7584
| `tests/` | Python unit tests for the arithmetic contract |
7685
| `docs/` | Architecture and verification notes |
7786

assets/rtl-regression.svg

Lines changed: 70 additions & 0 deletions
Loading

tools/render_readme_assets.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/env python3
2+
"""Render deterministic README evidence from the checked-in CI matrix."""
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
from pathlib import Path
8+
9+
from run_regression import corner_cases
10+
11+
12+
ROOT = Path(__file__).resolve().parents[1]
13+
OUTPUT = ROOT / "assets" / "rtl-regression.svg"
14+
SCENARIOS = ((1, 40), (8, 200), (17, 100))
15+
16+
17+
def render() -> str:
18+
rows = []
19+
for vec_len, random_cases in SCENARIOS:
20+
corners = len(corner_cases(vec_len))
21+
rows.append((vec_len, random_cases, corners, random_cases + corners))
22+
23+
max_total = max(total for _, _, _, total in rows)
24+
bars = []
25+
for index, (vec_len, random_cases, corners, total) in enumerate(rows):
26+
x = 126 + index * 190
27+
total_height = 300 * total / max_total
28+
corner_height = 300 * corners / max_total
29+
random_height = total_height - corner_height
30+
y_random = 474 - random_height
31+
y_corner = y_random - corner_height
32+
bars.append(
33+
f'''<g aria-label="VEC_LEN {vec_len}: {total} deterministic RTL transactions">
34+
<rect x="{x}" y="{y_random:.2f}" width="110" height="{random_height:.2f}" rx="8" fill="#e39a32"/>
35+
<rect x="{x}" y="{y_corner:.2f}" width="110" height="{corner_height:.2f}" rx="8" fill="#203c5b"/>
36+
<text x="{x + 55}" y="{y_corner - 14:.2f}" text-anchor="middle" class="value">{total}</text>
37+
<text x="{x + 55}" y="512" text-anchor="middle" class="axis">VEC_LEN {vec_len}</text>
38+
<text x="{x + 55}" y="538" text-anchor="middle" class="small">{corners} corner + {random_cases} random</text>
39+
</g>'''
40+
)
41+
42+
return f'''<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="620" viewBox="0 0 1280 620" role="img" aria-labelledby="title desc">
43+
<title id="title">Edge AI RTL Lab deterministic regression matrix</title>
44+
<desc id="desc">Stacked bars show corner and fixed-seed random transactions for vector lengths 1, 8, and 17. A verification panel lists ten Python model tests, Icarus RTL simulation, and a Yosys structural check.</desc>
45+
<style>
46+
.title {{ font: 700 34px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; fill: #13253b; }}
47+
.subtitle {{ font: 16px system-ui, sans-serif; fill: #566170; }}
48+
.axis {{ font: 700 16px system-ui, sans-serif; fill: #203c5b; }}
49+
.small {{ font: 14px system-ui, sans-serif; fill: #69717a; }}
50+
.value {{ font: 800 23px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; fill: #13253b; }}
51+
.panel-title {{ font: 700 19px system-ui, sans-serif; fill: #fff8e9; }}
52+
.panel-label {{ font: 14px system-ui, sans-serif; fill: #b9c7d4; }}
53+
.panel-value {{ font: 800 24px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; fill: #ffc56d; }}
54+
</style>
55+
<rect width="1280" height="620" rx="28" fill="#fbf6ec"/>
56+
<path d="M0 92 H1280" stroke="#e6dac3"/>
57+
<text x="62" y="54" class="title">VERIFICATION / REGRESSION MATRIX</text>
58+
<text x="62" y="81" class="subtitle">Checked-in CI workload — transaction count, not performance</text>
59+
60+
<g stroke="#e7dcc8" stroke-width="1">
61+
<path d="M74 474 H664"/><path d="M74 324 H664"/><path d="M74 174 H664"/>
62+
</g>
63+
<text x="76" y="157" class="small">211 max transactions</text>
64+
{''.join(bars)}
65+
66+
<g transform="translate(714 126)">
67+
<rect width="504" height="414" rx="22" fill="#13253b"/>
68+
<text x="34" y="49" class="panel-title">WHAT THE PIPELINE CHECKS</text>
69+
<path d="M34 70 H470" stroke="#39516a"/>
70+
71+
<text x="34" y="111" class="panel-label">Python golden-model unit tests</text>
72+
<text x="430" y="111" text-anchor="end" class="panel-value">10</text>
73+
74+
<text x="34" y="169" class="panel-label">RTL transactions across 3 parameter cases</text>
75+
<text x="430" y="169" text-anchor="end" class="panel-value">369</text>
76+
77+
<text x="34" y="227" class="panel-label">Pseudo-random seed</text>
78+
<text x="430" y="227" text-anchor="end" class="panel-value">0x5eed2339</text>
79+
80+
<text x="34" y="285" class="panel-label">Simulation</text>
81+
<text x="430" y="285" text-anchor="end" class="panel-value">Icarus</text>
82+
83+
<text x="34" y="343" class="panel-label">Structural synthesis sanity check</text>
84+
<text x="430" y="343" text-anchor="end" class="panel-value">Yosys</text>
85+
86+
<text x="34" y="386" class="panel-label">No timing, area, power, FPGA, or silicon claim</text>
87+
</g>
88+
89+
<g transform="translate(76 573)">
90+
<rect width="18" height="18" rx="4" fill="#203c5b"/><text x="28" y="15" class="small">named corner cases</text>
91+
<rect x="202" width="18" height="18" rx="4" fill="#e39a32"/><text x="230" y="15" class="small">fixed-seed random cases</text>
92+
</g>
93+
</svg>
94+
'''
95+
96+
97+
def main() -> None:
98+
parser = argparse.ArgumentParser(description=__doc__)
99+
parser.add_argument("--check", action="store_true", help="fail if the committed SVG is stale")
100+
args = parser.parse_args()
101+
expected = render()
102+
103+
if args.check:
104+
if not OUTPUT.exists() or OUTPUT.read_text(encoding="utf-8") != expected:
105+
raise SystemExit(f"stale generated asset: {OUTPUT.relative_to(ROOT)}")
106+
print(f"up to date: {OUTPUT.relative_to(ROOT)}")
107+
return
108+
109+
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
110+
OUTPUT.write_text(expected, encoding="utf-8")
111+
print(f"wrote {OUTPUT.relative_to(ROOT)}")
112+
113+
114+
if __name__ == "__main__":
115+
main()

0 commit comments

Comments
 (0)