mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
- Introduced test status signals (test_done_o, test_pass_o, test_code_o) in sysctrl interface and module. - Updated memory map to include TEST_STATUS offset. - Enhanced retrosoc_tb to monitor test completion and report results. - Modified Emulator to handle test status and return appropriate exit codes. - Updated formal verification to include assertions for test status. - Added CoreMark log parsing script and integrated it into the regression tests. - Implemented tests for test status handling in sysctrl_fault_tb. - Adjusted simulation success and failure markers in various scripts and tests. - Ensured compatibility with existing performance logging and regression testing frameworks.
105 lines
3.7 KiB
Python
105 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Convert the quick Hazard3 CoreMark UART report into structured JSON."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
import sys
|
|
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
|
|
from pathlib import Path
|
|
|
|
|
|
RESULT_PREFIX = "COREMARK_RESULT "
|
|
PASS_MARKER = "COREMARK_PASS"
|
|
FAIL_PREFIX = "COREMARK_FAIL"
|
|
REQUIRED_FIELDS = {"mode", "qualified", "memory", "iterations", "cycles", "cpu_hz"}
|
|
TOKEN = re.compile(r"([a-z_]+)=([^\s]+)")
|
|
|
|
|
|
def parse_number(value: str) -> int:
|
|
return int(value, 0)
|
|
|
|
|
|
def parse_log(content: str) -> dict[str, object]:
|
|
results: list[dict[str, object]] = []
|
|
for line in content.splitlines():
|
|
if not line.startswith(RESULT_PREFIX):
|
|
continue
|
|
fields = {name: value for name, value in TOKEN.findall(line)}
|
|
missing = REQUIRED_FIELDS.difference(fields)
|
|
if missing:
|
|
raise ValueError(f"CoreMark result is missing fields: {sorted(missing)}")
|
|
mode = fields["mode"]
|
|
if mode not in {"quick", "standard"}:
|
|
raise ValueError(f"unsupported CoreMark mode: {mode}")
|
|
memory = fields["memory"]
|
|
if memory != "sram":
|
|
raise ValueError(f"CoreMark result must execute from SRAM, got: {memory}")
|
|
qualified = parse_number(fields["qualified"])
|
|
if qualified not in {0, 1}:
|
|
raise ValueError("CoreMark qualified flag must be zero or one")
|
|
iterations = parse_number(fields["iterations"])
|
|
cycles = parse_number(fields["cycles"])
|
|
cpu_hz = parse_number(fields["cpu_hz"])
|
|
if iterations <= 0 or cycles <= 0 or cpu_hz <= 0:
|
|
raise ValueError("CoreMark iterations, cycles, and cpu_hz must be positive")
|
|
try:
|
|
score = (Decimal(iterations) * Decimal(1_000_000) / Decimal(cycles)).quantize(
|
|
Decimal("0.001"), rounding=ROUND_HALF_UP
|
|
)
|
|
except (InvalidOperation, ZeroDivisionError) as error:
|
|
raise ValueError("invalid CoreMark score inputs") from error
|
|
results.append(
|
|
{
|
|
"mode": mode,
|
|
"qualified": bool(qualified),
|
|
"memory": memory,
|
|
"iterations": iterations,
|
|
"cycles": cycles,
|
|
"cpu_hz": cpu_hz,
|
|
"coremark_per_mhz": str(score),
|
|
}
|
|
)
|
|
|
|
pass_marker = PASS_MARKER in content
|
|
failure_marker = any(line.startswith(FAIL_PREFIX) for line in content.splitlines())
|
|
quick_results = [result for result in results if result["mode"] == "quick"]
|
|
passed = pass_marker and not failure_marker and len(quick_results) == 1
|
|
return {
|
|
"schema_version": 1,
|
|
"status": "passed" if passed else "failed",
|
|
"failure_marker": failure_marker,
|
|
"pass_marker": pass_marker,
|
|
"results": results,
|
|
}
|
|
|
|
|
|
def atomic_write(path: Path, content: str) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
temporary = path.with_suffix(path.suffix + ".tmp")
|
|
temporary.write_text(content, encoding="utf-8")
|
|
temporary.replace(path)
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--log", type=Path, required=True)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
report = parse_log(args.log.read_text(encoding="utf-8", errors="replace"))
|
|
atomic_write(args.output, json.dumps(report, indent=2, sort_keys=True) + "\n")
|
|
if report["status"] != "passed":
|
|
print("CoreMark did not emit one complete quick passing report", file=sys.stderr)
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|