|
| 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