Files
retroSoC/publications/format_reference.py
T
maksyuki a28b3ce11a feat: update NPU integration and validation in publications
- Modified waveforms.json to reflect changes in resource tracking from nine to ten positions for both resource-controller integration and reference monitor parameters.
- Enhanced dev_reference.py to include NPU sources and updated CI snapshot validation to accommodate new statuses and conclusions.
- Added example NPU implementation in npu.c for job submission and result handling.
- Updated format_reference.py to validate NPU descriptor word offsets against RTL definitions.
- Adjusted storage_reference.py to reflect changes in APU and NPU local memory configurations.
- Enhanced system_reference.py to include NPU implementation details and validate accelerator claims.
- Updated tests to reflect changes in the structure and coverage of NPU and APU components, ensuring accurate validation of configurations and claims.
- Introduced new tests in v05.py to ensure distinct handling of executable configurations and evidence for NPU and APU.
2026-09-22 14:50:41 +08:00

90 lines
5.1 KiB
Python

"""Publication-only binary layouts, resolved from C structures and existing exporters."""
from __future__ import annotations
import copy
import json
import re
from pathlib import Path
from publications.implementation_reference import without_comments
def structure_fields(root: Path, specification: dict) -> list[dict]:
source = without_comments((root / specification["file"]).read_text(encoding="utf-8"))
bodies = re.findall(r"typedef\s+struct\s*\{([^}]+)\}\s*" + re.escape(specification["name"]) + r"\s*;", source)
if len(bodies) != 1:
raise ValueError("binary-layout C structure missing or ambiguous")
pattern = r"(u?int)(8|16|32|64)_t\s+(\w+)\s*(?:\[\s*(\d+)\s*\])?\s*;"
if re.sub(pattern, "", bodies[0]).strip():
raise ValueError("unreviewed type in binary-layout C structure")
result, offset = [], 0
for signed, width, member, count in re.findall(pattern, bodies[0]):
bits, count = int(width), int(count or "1")
if count < 1 or offset % (bits // 8):
raise ValueError("binary-layout structure needs an explicit padding/alignment review")
role = "reserved" if member.startswith("reserved") else "writeback" if member in specification.get("writeback", []) else "mixed" if member in specification.get("mixed", []) else "configuration"
for index in range(count):
name = member if count == 1 else f"{member}[{index}]"
result.append({"name": name, "label": name, "member": member, "array_index": index if count > 1 else None,
"offset": offset, "lsb": offset * 8, "bits": bits,
"role": role, "signed": signed == "int"})
offset += bits // 8
if offset != specification["bytes"]:
raise ValueError("binary-layout C structure size changed")
return result
def word_fields(fields: list[dict]) -> list[dict]:
return [{"name": row["name"], "label": row["name"], "offset": row["offset"],
"lsb": row["offset"] * 8, "bits": row["bytes"] * 8,
"role": "reserved" if row["name"].startswith("reserved") else "configuration"}
for row in fields]
def collect_layouts(root: Path, catalog_path: str, system: dict) -> dict[str, dict]:
catalog = json.loads((root / catalog_path).read_text(encoding="utf-8"))
result = {}
product_formats = {row["id"]: row for row in system["product_details"]["formats"]}
for specification in catalog:
record = copy.deepcopy(specification)
identifier = record["id"]
if identifier in result or not record.get("chapters") or not record.get("sources"):
raise ValueError("duplicate binary layout or missing chapter/source")
if record.get("structure"):
record["fields"] = structure_fields(root, record["structure"])
record["bits"] = record["structure"]["bytes"] * 8
if record.get("derived") in {"hp-header", "hp-entry"}:
bundle = system["software"]["bundle_reference"]
key = "header_fields" if record["derived"] == "hp-header" else "entry_fields"
record["fields"] = word_fields(bundle[key])
record["bits"] = sum(field["bits"] for field in record["fields"])
if record.get("derived") == "npu-descriptor":
from publications.storage_reference import constants
host = (root / "scripts/npu_descriptors.py").read_text(encoding="utf-8")
words = {int(index): name.lower() for name, index in re.findall(r"^WORD_(\w+):\s*Final\s*=\s*(\d+)", host, re.M)}
rtl = constants(root, "rtl/ip/multimedia/npu_define.svh")
for index, name in words.items():
suffix = "RESERVED" if name == "reserved1" else name.upper()
if rtl.get("APB4_NPU__DESCRIPTOR_WORD_" + suffix) != index:
raise ValueError("NPU descriptor word offset differs between host and RTL")
if set(words) != set(range(26)):
raise ValueError("NPU descriptor documented word inventory changed")
for index in range(26, 32):
words[index] = f"reserved{index}"
record["fields"] = [{"name": name, "label": name.replace("_", " "), "lsb": index * 32,
"bits": 32, "role": "reserved" if name.startswith("reserved") else "configuration"}
for index, name in sorted(words.items())]
record["bits"] = rtl["APB4_NPU__DESCRIPTOR_BYTES_VALUE"] * 8
if record.get("product_format"):
original = product_formats[record["product_format"]]
record["note"] = original["layout"] + " " + original["boundary"]
record["sources"] = sorted(set(record["sources"]) | set(original["sources"]))
record["bindings"] = record.get("bindings", []) + original["bindings"]
if record["kind"] == "bytes":
for field in record["fields"]:
field["offset"] = field["lsb"] // 8
if field["lsb"] % 8 or field["bits"] % 8:
raise ValueError("byte layout contains a non-byte-aligned field")
result[identifier] = record
return result