mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add CRYPTO-P2 targets and reporting script for synthesis, netlist, and STA validation
This commit is contained in:
5 files changed
+172
-1
No files matched your search
@@ -431,7 +431,7 @@ crypto-p0-baseline: manifest
|
|||||||
crypto-p0-report: manifest
|
crypto-p0-report: manifest
|
||||||
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p0.py report --variant-root $(VARIANT_ROOT)
|
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p0.py report --variant-root $(VARIANT_ROOT)
|
||||||
|
|
||||||
.PHONY: crypto-p1-constants crypto-p1-rtl crypto-p1-formal crypto-p1-synth crypto-p1-report
|
.PHONY: crypto-p1-constants crypto-p1-rtl crypto-p1-formal crypto-p1-synth crypto-p1-report crypto-p2-synth crypto-p2-netlist crypto-p2-sta crypto-p2-report
|
||||||
crypto-p1-constants: manifest
|
crypto-p1-constants: manifest
|
||||||
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p1.py constants --variant-root $(VARIANT_ROOT)
|
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p1.py constants --variant-root $(VARIANT_ROOT)
|
||||||
crypto-p1-rtl: manifest
|
crypto-p1-rtl: manifest
|
||||||
@@ -451,6 +451,25 @@ crypto-p1-report: manifest
|
|||||||
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p1.py report --variant-root $(VARIANT_ROOT) \
|
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p1.py report --variant-root $(VARIANT_ROOT) \
|
||||||
--baseline-root $(CRYPTO_P0_BASELINE_ROOT) --lp-variant-root $(CRYPTO_P1_LP_ROOT) \
|
--baseline-root $(CRYPTO_P0_BASELINE_ROOT) --lp-variant-root $(CRYPTO_P1_LP_ROOT) \
|
||||||
$(if $(CRYPTO_P1_CI_ROOT),--ci-variant-root $(CRYPTO_P1_CI_ROOT),)
|
$(if $(CRYPTO_P1_CI_ROOT),--ci-variant-root $(CRYPTO_P1_CI_ROOT),)
|
||||||
|
CRYPTO_P1_ROOT ?= $(VARIANT_ROOT)
|
||||||
|
CRYPTO_P2_NETLIST_ROOT ?= $(VARIANT_ROOT)
|
||||||
|
CRYPTO_P2_STA_ROOT ?= $(VARIANT_ROOT)
|
||||||
|
CRYPTO_P2_PHYSICAL_ROOT ?= $(VARIANT_ROOT)
|
||||||
|
crypto-p2-synth: manifest
|
||||||
|
$(MAKE) CONFIG=$(ROOT_PATH)/configs/ci/ihp130.mk BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
||||||
|
SYNTH=YOSYS SYNTH_RECIPE=balanced synth
|
||||||
|
crypto-p2-netlist: manifest
|
||||||
|
$(MAKE) CONFIG=$(ROOT_PATH)/configs/ci/ihp130.mk BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
||||||
|
APP=bringup APP_SRCS=$(ROOT_PATH)/tests/c/crypto_firmware.c LINK_TYPE=ld2_all_sram \
|
||||||
|
SIMU=IVERILOG SYNTH=YOSYS HAVE_SVA=YES firmware netcomp netsim
|
||||||
|
crypto-p2-sta: manifest
|
||||||
|
$(MAKE) CONFIG=$(ROOT_PATH)/configs/ci/ihp130.mk BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
||||||
|
SYNTH=YOSYS STA=OPENSTA synth sta
|
||||||
|
crypto-p2-report: manifest
|
||||||
|
$(PYTHON) $(ROOT_PATH)/scripts/crypto_p2.py report --variant-root $(VARIANT_ROOT) \
|
||||||
|
--p0-root $(CRYPTO_P0_BASELINE_ROOT) --p1-root $(CRYPTO_P1_ROOT) \
|
||||||
|
--netlist-root $(CRYPTO_P2_NETLIST_ROOT) --sta-root $(CRYPTO_P2_STA_ROOT) \
|
||||||
|
--physical-root $(CRYPTO_P2_PHYSICAL_ROOT)
|
||||||
|
|
||||||
.PHONY: help config doctor setup setup-regression setup-mpw setup-vexiiriscv setup-clusterip setup-ip setup-pdk setup-app setup-apu-reference setup-apu-kws-reference apu-p5-bundle apu-p5-corpus apu-p7-model apu-p9-coefficients apu-p9-evidence apu-p9-memory-ab setup-hp-linux hp-linux hp-bundle hp-linux-sim hp-smoke-bundle hp-smoke-sim hp-apu-bundle hp-apu-sim \
|
.PHONY: help config doctor setup setup-regression setup-mpw setup-vexiiriscv setup-clusterip setup-ip setup-pdk setup-app setup-apu-reference setup-apu-kws-reference apu-p5-bundle apu-p5-corpus apu-p7-model apu-p9-coefficients apu-p9-evidence apu-p9-memory-ab setup-hp-linux hp-linux hp-bundle hp-linux-sim hp-smoke-bundle hp-smoke-sim hp-apu-bundle hp-apu-sim \
|
||||||
clean-all purge-cache manifest check-warnings metrics check-metrics package commercial-package \
|
clean-all purge-cache manifest check-warnings metrics check-metrics package commercial-package \
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ functioning macro responses and a running clock; they do not establish SRAM
|
|||||||
analog correctness, arbitrary silicon fault tolerance, DPA/FIA resistance or
|
analog correctness, arbitrary silicon fault tolerance, DPA/FIA resistance or
|
||||||
physical timing. P2 still owns full-chip synthesis, functional netlist
|
physical timing. P2 still owns full-chip synthesis, functional netlist
|
||||||
simulation, STA, physical views and isolated clean-revision A/B measurement.
|
simulation, STA, physical views and isolated clean-revision A/B measurement.
|
||||||
|
The `crypto-p2-report` target is fail-closed on the same clean-revision and
|
||||||
|
artifact requirements; it cannot convert a dirty worktree or missing netlist,
|
||||||
|
STA or physical result into a qualification PASS.
|
||||||
|
|
||||||
Run the committed `configs/ci/ihp130.mk` profile through `crypto-p1-rtl`,
|
Run the committed `configs/ci/ihp130.mk` profile through `crypto-p1-rtl`,
|
||||||
`crypto-p1-formal` and `crypto-p1-synth`, then the recorded LP/CI firmware runs
|
`crypto-p1-formal` and `crypto-p1-synth`, then the recorded LP/CI firmware runs
|
||||||
|
|||||||
@@ -882,6 +882,24 @@ make CONFIG=configs/ci/ihp130.mk librelane-doctor
|
|||||||
git diff --check
|
git diff --check
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The Crypto-specific P2 wrappers are:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS BUILD_TIMESTAMP=<candidate-timestamp> crypto-p2-synth
|
||||||
|
make CONFIG=configs/ci/ihp130.mk BUILD_TIMESTAMP=<candidate-timestamp> crypto-p2-netlist
|
||||||
|
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS STA=OPENSTA BUILD_TIMESTAMP=<candidate-timestamp> crypto-p2-sta
|
||||||
|
make CONFIG=configs/ci/ihp130.mk BUILD_TIMESTAMP=<candidate-timestamp> \
|
||||||
|
CRYPTO_P0_BASELINE_ROOT=build/<p0-variant> CRYPTO_P1_ROOT=build/<p1-variant> \
|
||||||
|
CRYPTO_P2_NETLIST_ROOT=build/<netlist-variant> CRYPTO_P2_STA_ROOT=build/<sta-variant> \
|
||||||
|
CRYPTO_P2_PHYSICAL_ROOT=build/<physical-variant> crypto-p2-report
|
||||||
|
```
|
||||||
|
|
||||||
|
`crypto-p2-netlist` runs the public `tests/c/crypto_firmware.c` image through
|
||||||
|
the Icarus synthesized SoC netlist, so Crypto is exercised through LP APB/DMA
|
||||||
|
and no RTL hierarchy or SRAM preload. The P2 report is fail-closed: a dirty
|
||||||
|
candidate, missing netlist/STA/physical artifact, mismatched profile, stale
|
||||||
|
P1 evidence or absent P0 report produces `incomplete`, never PASS.
|
||||||
|
|
||||||
Use a single explicit BUILD_TIMESTAMP for commands that must consume the same
|
Use a single explicit BUILD_TIMESTAMP for commands that must consume the same
|
||||||
variant; behavioral and synthesis configuration differences must be recorded.
|
variant; behavioral and synthesis configuration differences must be recorded.
|
||||||
Python tooling changes additionally require Ruff/Pytest under repository
|
Python tooling changes additionally require Ruff/Pytest under repository
|
||||||
|
|||||||
@@ -209,6 +209,9 @@ build/simulation and binds the actual configuration, input snapshot, ELF and
|
|||||||
log/result hashes. `crypto_p1.py quality --variant-root <variant>` records
|
log/result hashes. `crypto_p1.py quality --variant-root <variant>` records
|
||||||
focused formatter and policy results. Report assembly rejects stale inputs
|
focused formatter and policy results. Report assembly rejects stale inputs
|
||||||
or artifacts; it cannot qualify an earlier binary using current source hashes.
|
or artifacts; it cannot qualify an earlier binary using current source hashes.
|
||||||
|
`crypto_p2.py` is the fail-closed P2 aggregator. It requires a clean candidate
|
||||||
|
revision and records whole-SoC netlist, STA, physical, metrics, warning and
|
||||||
|
P0/P1 evidence; missing P2 artifacts remain `NOT_RUN`.
|
||||||
|
|
||||||
Update or add tests in [`../tests`](../tests) for script behavior. Run
|
Update or add tests in [`../tests`](../tests) for script behavior. Run
|
||||||
`ruff check .` and `python3 -m pytest -q`; build-flow changes also require the
|
`ruff check .` and `python3 -m pytest -q`; build-flow changes also require the
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Fail-closed CRYPTO-P2 synthesis, netlist, STA and physical evidence report."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
BASELINE_REVISION = "92830d963da2f1e39bb219c0d377bc4889c07755"
|
||||||
|
|
||||||
|
|
||||||
|
def digest(path: Path) -> str:
|
||||||
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def dump(path: Path, value: object) -> None:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(value, indent=2, sort_keys=True) + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def manifest(root: Path) -> dict:
|
||||||
|
path = root / "meta/manifest.json"
|
||||||
|
return json.loads(path.read_text()) if path.exists() else {}
|
||||||
|
|
||||||
|
|
||||||
|
def clean_revision() -> tuple[bool, str]:
|
||||||
|
status = subprocess.check_output(["git", "status", "--porcelain"], cwd=ROOT, text=True)
|
||||||
|
head = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip()
|
||||||
|
return not status, head
|
||||||
|
|
||||||
|
|
||||||
|
def artifact(path: Path, expected_status: str | None = None) -> dict:
|
||||||
|
if not path.exists():
|
||||||
|
return {"status": "NOT_RUN", "path": str(path)}
|
||||||
|
try:
|
||||||
|
value = json.loads(path.read_text())
|
||||||
|
except (OSError, json.JSONDecodeError) as error:
|
||||||
|
return {"status": "INVALID", "path": str(path), "error": str(error)}
|
||||||
|
value.setdefault("path", str(path))
|
||||||
|
if expected_status is not None and value.get("status") != expected_status:
|
||||||
|
value["status_check"] = "failed"
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def report(args: argparse.Namespace) -> int:
|
||||||
|
variant = args.variant_root.resolve()
|
||||||
|
p1 = args.p1_root.resolve()
|
||||||
|
p0 = args.p0_root.resolve()
|
||||||
|
is_clean, head = clean_revision()
|
||||||
|
candidate_manifest = manifest(variant)
|
||||||
|
p1_report = artifact(p1 / "crypto/p1/p1-report.json")
|
||||||
|
synth = artifact(p1 / "crypto/p1/candidate-synthesis.json")
|
||||||
|
netlist = artifact(args.netlist_root.resolve() / "sim/iverilog/netl/result-sim-check.json")
|
||||||
|
sta = artifact(args.sta_root.resolve() / "sta/opensta/result-sta.json")
|
||||||
|
physical = artifact(args.physical_root.resolve() / "crypto/p2/physical.json")
|
||||||
|
metrics = artifact(variant / "meta/metrics.json")
|
||||||
|
warnings = artifact(variant / "meta/warnings.json")
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"clean_candidate": is_clean,
|
||||||
|
"candidate_manifest": candidate_manifest.get("profile") == "ihp130",
|
||||||
|
"candidate_revision": bool(head) and head != BASELINE_REVISION,
|
||||||
|
"p0_report": artifact(p0 / "crypto/p0/p0-report.json").get("status") == "passed",
|
||||||
|
"p1_focused": p1_report.get("focused_gates_status") == "passed",
|
||||||
|
"block_synthesis": synth.get("status") == "passed",
|
||||||
|
"whole_soc_netlist": netlist.get("status") == "passed",
|
||||||
|
"sta": sta.get("status") == "passed",
|
||||||
|
"physical": physical.get("status") == "passed",
|
||||||
|
"metrics": metrics.get("status") == "passed",
|
||||||
|
"warnings": warnings.get("status") in ("passed", "observed"),
|
||||||
|
}
|
||||||
|
required = ("clean_candidate", "candidate_manifest", "candidate_revision", "p0_report",
|
||||||
|
"p1_focused", "block_synthesis", "whole_soc_netlist", "sta", "physical")
|
||||||
|
passed = all(checks[name] for name in required)
|
||||||
|
result = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"feature": "crypto",
|
||||||
|
"phase": "CRYPTO-P2",
|
||||||
|
"status": "passed" if passed else "incomplete",
|
||||||
|
"verdict": "P2_ACCEPTED" if passed else "NOT_RUN_OR_INCOMPLETE",
|
||||||
|
"baseline_revision": BASELINE_REVISION,
|
||||||
|
"candidate_revision": head,
|
||||||
|
"candidate_dirty": not is_clean,
|
||||||
|
"profile": candidate_manifest.get("profile", "NOT_RUN"),
|
||||||
|
"configuration": candidate_manifest.get("configuration", {}),
|
||||||
|
"checks": checks,
|
||||||
|
"artifacts": {
|
||||||
|
"p0_report": str(p0 / "crypto/p0/p0-report.json"),
|
||||||
|
"p1_report": str(p1 / "crypto/p1/p1-report.json"),
|
||||||
|
"synthesis": synth,
|
||||||
|
"netlist": netlist,
|
||||||
|
"sta": sta,
|
||||||
|
"physical": physical,
|
||||||
|
"metrics": metrics,
|
||||||
|
"warnings": warnings,
|
||||||
|
},
|
||||||
|
"gaps": [name for name, value in checks.items() if not value],
|
||||||
|
"non_goals": ["Pytest under maintainer constraint", "CRYPTO-P3 commercial variants",
|
||||||
|
"DPA/FIA/physical security signoff"],
|
||||||
|
}
|
||||||
|
dump(variant / "crypto/p2/p2-report.json", result)
|
||||||
|
return 0 if passed else 2
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("command", choices=("report",))
|
||||||
|
parser.add_argument("--variant-root", type=Path, required=True)
|
||||||
|
parser.add_argument("--p0-root", type=Path, required=True)
|
||||||
|
parser.add_argument("--p1-root", type=Path, required=True)
|
||||||
|
parser.add_argument("--netlist-root", type=Path)
|
||||||
|
parser.add_argument("--sta-root", type=Path)
|
||||||
|
parser.add_argument("--physical-root", type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
args.netlist_root = args.netlist_root or args.variant_root
|
||||||
|
args.sta_root = args.sta_root or args.variant_root
|
||||||
|
args.physical_root = args.physical_root or args.variant_root
|
||||||
|
if args.command == "report":
|
||||||
|
return report(args)
|
||||||
|
raise AssertionError(args.command)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in new issue
Block a user