mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-05 06:32:37 +00:00
- 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.
90 lines
5.1 KiB
Python
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
|