From 422c4555fbd99a0b45cc51925e0f8c548ce27bfc Mon Sep 17 00:00:00 2001
From: HiddenTrojan <93521146+Labeeb2339@users.noreply.github.com>
Date: Wed, 22 Jul 2026 22:55:37 +0800
Subject: [PATCH] docs: visualize deterministic RTL regression
---
.github/workflows/ci.yml | 3 +
README.md | 9 +++
assets/rtl-regression.svg | 70 +++++++++++++++++++++
tools/render_readme_assets.py | 115 ++++++++++++++++++++++++++++++++++
4 files changed, 197 insertions(+)
create mode 100644 assets/rtl-regression.svg
create mode 100644 tools/render_readme_assets.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d94549c..0da35a3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,6 +30,9 @@ jobs:
- name: Test Python golden model
run: python -m unittest discover -s tests -v
+ - name: Check generated README evidence
+ run: python tools/render_readme_assets.py --check
+
- name: Regress single-lane parameter case
run: python tools/run_regression.py --sim iverilog --vec-len 1 --random-cases 40
diff --git a/README.md b/README.md
index cfcc00b..649215a 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,14 @@ I kept the scope deliberately small: parameterized SystemVerilog, ready/valid
control, a bit-exact Python reference model, deterministic regression, and CI.
This is **not** a trained AI model or a complete neural-network accelerator.
+
+
+
+
+The figure is generated from the checked-in CI matrix. It counts verification
+transactions; it is not a throughput, timing, area, power, FPGA, or silicon
+benchmark.
+
## What is implemented
- Synthesizable SystemVerilog with configurable vector length
@@ -72,6 +80,7 @@ lane. See [Architecture](docs/architecture.md) for timing and width details.
| `model/dot_product_model.py` | Bit-exact reference arithmetic and packing |
| `tb/tb_int8_dot_product.sv` | Self-checking ready/valid testbench |
| `tools/run_regression.py` | Vector generation, compile, and simulation harness |
+| `tools/render_readme_assets.py` | Rebuilds and checks the README evidence figure |
| `tests/` | Python unit tests for the arithmetic contract |
| `docs/` | Architecture and verification notes |
diff --git a/assets/rtl-regression.svg b/assets/rtl-regression.svg
new file mode 100644
index 0000000..d55250e
--- /dev/null
+++ b/assets/rtl-regression.svg
@@ -0,0 +1,70 @@
+
diff --git a/tools/render_readme_assets.py b/tools/render_readme_assets.py
new file mode 100644
index 0000000..36ed757
--- /dev/null
+++ b/tools/render_readme_assets.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+"""Render deterministic README evidence from the checked-in CI matrix."""
+
+from __future__ import annotations
+
+import argparse
+from pathlib import Path
+
+from run_regression import corner_cases
+
+
+ROOT = Path(__file__).resolve().parents[1]
+OUTPUT = ROOT / "assets" / "rtl-regression.svg"
+SCENARIOS = ((1, 40), (8, 200), (17, 100))
+
+
+def render() -> str:
+ rows = []
+ for vec_len, random_cases in SCENARIOS:
+ corners = len(corner_cases(vec_len))
+ rows.append((vec_len, random_cases, corners, random_cases + corners))
+
+ max_total = max(total for _, _, _, total in rows)
+ bars = []
+ for index, (vec_len, random_cases, corners, total) in enumerate(rows):
+ x = 126 + index * 190
+ total_height = 300 * total / max_total
+ corner_height = 300 * corners / max_total
+ random_height = total_height - corner_height
+ y_random = 474 - random_height
+ y_corner = y_random - corner_height
+ bars.append(
+ f'''
+
+
+ {total}
+ VEC_LEN {vec_len}
+ {corners} corner + {random_cases} random
+'''
+ )
+
+ return f'''
+'''
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--check", action="store_true", help="fail if the committed SVG is stale")
+ args = parser.parse_args()
+ expected = render()
+
+ if args.check:
+ if not OUTPUT.exists() or OUTPUT.read_text(encoding="utf-8") != expected:
+ raise SystemExit(f"stale generated asset: {OUTPUT.relative_to(ROOT)}")
+ print(f"up to date: {OUTPUT.relative_to(ROOT)}")
+ return
+
+ OUTPUT.parent.mkdir(parents=True, exist_ok=True)
+ OUTPUT.write_text(expected, encoding="utf-8")
+ print(f"wrote {OUTPUT.relative_to(ROOT)}")
+
+
+if __name__ == "__main__":
+ main()