Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)
Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog TBs, fidelity attribution tooling. Functional baseline before removing the dead bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fail closed if a runtime-CLUT fit has timed out a required fabric branch."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
DEFAULT_OUTPUT = Path(
|
||||
"synth/de25_nano/top_psmct32_raster_demo/output_files"
|
||||
)
|
||||
REVISION = "de25_nano_psmct32_raster_demo_top"
|
||||
|
||||
|
||||
def read(path: Path) -> str:
|
||||
try:
|
||||
return path.read_text(encoding="utf-8", errors="replace")
|
||||
except OSError as exc:
|
||||
raise SystemExit(f"FAIL: cannot read {path}: {exc}") from exc
|
||||
|
||||
|
||||
def summary_value(text: str, label: str) -> int:
|
||||
match = re.search(rf"^{re.escape(label)}\s*:\s*([0-9,]+)\s*/", text, re.M)
|
||||
if not match:
|
||||
raise SystemExit(f"FAIL: missing '{label}' in fit summary")
|
||||
return int(match.group(1).replace(",", ""))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT)
|
||||
args = parser.parse_args()
|
||||
|
||||
fit_summary = args.output_dir / f"{REVISION}.fit.summary"
|
||||
fit_report = args.output_dir / f"{REVISION}.fit.rpt"
|
||||
sta_summary = args.output_dir / f"{REVISION}.sta.summary"
|
||||
summary = read(fit_summary)
|
||||
fit = read(fit_report)
|
||||
sta = read(sta_summary)
|
||||
|
||||
failures: list[str] = []
|
||||
if "Fitter Status : Successful" not in summary:
|
||||
failures.append("fitter did not report success")
|
||||
|
||||
alms = summary_value(summary, "Logic utilization (in ALMs)")
|
||||
rams = summary_value(summary, "Total RAM Blocks")
|
||||
# A 640x480 persistent-Z runtime scene normally consumes roughly 79% ALMs
|
||||
# and 74% M20Ks. These deliberately loose floors catch path pruning, not
|
||||
# healthy placement variation.
|
||||
if alms < 20_000:
|
||||
failures.append(f"only {alms:,} ALMs; runtime raster fabric appears pruned")
|
||||
if rams < 150:
|
||||
failures.append(f"only {rams} RAM blocks; runtime texture/Z fabric appears pruned")
|
||||
|
||||
for name in ("u_demo|g_feeder", "u_texcache|tex_mem", "u_zc_emit|u_req"):
|
||||
if name not in fit:
|
||||
failures.append(f"required fitted hierarchy missing: {name}")
|
||||
|
||||
for warning in (
|
||||
"feeder staging RAM dest EMPTY",
|
||||
"tex_mem dst matched 0 keepers",
|
||||
):
|
||||
if warning in fit:
|
||||
failures.append(f"runtime SDC endpoint missing: {warning}")
|
||||
|
||||
emif_setup = re.search(
|
||||
r"Type\s*:\s*Setup 'u_emif_lpddr4b\|iopll\|iopll_0_outclk0'\s*\n"
|
||||
r"Slack\s*:\s*([+-]?[0-9.]+)\s*\n"
|
||||
r"TNS\s*:\s*([+-]?[0-9.]+)",
|
||||
sta,
|
||||
)
|
||||
if not emif_setup:
|
||||
failures.append("missing 310 MHz EMIF setup summary")
|
||||
else:
|
||||
setup_slack, setup_tns = map(float, emif_setup.groups())
|
||||
if setup_slack < 0 or setup_tns < 0:
|
||||
failures.append(
|
||||
f"310 MHz setup fails: slack {setup_slack:+.3f} ns, TNS {setup_tns:+.3f} ns"
|
||||
)
|
||||
|
||||
if failures:
|
||||
print("RUNTIME FABRIC FIT: FAIL")
|
||||
for failure in failures:
|
||||
print(f"- {failure}")
|
||||
return 1
|
||||
|
||||
print(
|
||||
"RUNTIME FABRIC FIT: PASS "
|
||||
f"({alms:,} ALMs, {rams} RAM blocks, feeder/texture/Z present, 310 MHz setup met)"
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user