From 32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sat, 3 Oct 2026 14:05:38 -0400 Subject: vgsp: host CUDA bridge + sema release recovery; greeneye simulator wave - kernel: gsp_cuda_bridge (QMD launch capture, debugfs job/out/done, param+output resolution cached from inline writes), sema drain fixes (never hold/starve a channel), GR ring autopin + counter autoreg, per-page push reads, counter-derive gate; module builds clean - tools/cuda-bridge: CUDA driver-API daemon executing mail/vadd kernels on the physical GPU, CUBB2/CBD2 v2 protocol, layout check + self-tests - tools/guest-diag + tools/cuda-ab: scanner/pin fixes, victory push-only mode - debug/risc-v-gsp-rm-vm: Phase S simulator wave (GSP device model, boot ladder, triage/re-demo harnesses, docs 30-41), GPGPU-sim scaffolding - STATE-CURRENT/docs updates --- debug/risc-v-gsp-rm-vm/sim/devices/csb.py | 89 +++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 debug/risc-v-gsp-rm-vm/sim/devices/csb.py (limited to 'debug/risc-v-gsp-rm-vm/sim/devices/csb.py') diff --git a/debug/risc-v-gsp-rm-vm/sim/devices/csb.py b/debug/risc-v-gsp-rm-vm/sim/devices/csb.py new file mode 100644 index 0000000..818a263 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/sim/devices/csb.py @@ -0,0 +1,89 @@ +"""CSB / TRANSCOM message-window seam (B3 landing point). + +Evidence kind: **hardware register/field header + observed access pattern** +(once the firmware reaches the message loop). At the time of writing the +570.144 boot has not been observed polling the GSP message-queue CSB window, +so this module deliberately models **no register semantics by default**: a +window is only served when a profile declares it *and* lists the individual +registers with their widths, reset values and semantics (``rw``, ``w1c``, +``set``, ``clear``). Undeclared offsets stay unhandled and are logged. + +The CSB/TRANSCOM window carries the host<->GSP message queues and doorbells +(head/tail pointers, interrupt set/clear); B3 requires the first such poll to +return the documented read-back, which will be added here together with the +observed access evidence and a test. +""" +from __future__ import annotations + +from .base import Device + +#: Per-register semantics accepted by a profile. +SEMANTICS = ("rw", "ro", "wo", "w1c", "set", "clear") + + +class CsbWindow(Device): + """Profile-declared CSB/mailbox register window (empty by default).""" + + name = "csb" + + def __init__(self, *, base: int = 0, size: int = 0x1000, registers=None): + super().__init__(base=base, size=size) + # registers: {offset: {"width": 4, "value": int, "semantics": "rw"}} + self.registers: dict[int, dict] = {} + for off, spec in (registers or {}).items(): + self.declare(int(off), spec) + self.reset() + + def declare(self, offset: int, spec: dict) -> None: + semantics = spec.get("semantics", "rw") + if semantics not in SEMANTICS: + raise ValueError(f"unknown CSB semantics {semantics!r}") + width = int(spec.get("width", 4)) + if width not in (1, 2, 4, 8): + raise ValueError(f"unsupported CSB register width {width}") + self.registers[offset] = { + "width": width, + "reset": int(spec.get("value", 0)), + "semantics": semantics, + } + + def reset(self) -> None: + self.values = {off: spec["reset"] for off, spec in self.registers.items()} + + def _spec(self, offset: int, size: int) -> dict | None: + spec = self.registers.get(offset) + if spec is None or spec["width"] != size: + return None + return spec + + def read(self, offset: int, size: int) -> int | None: + spec = self._spec(offset, size) + if spec is None or spec["semantics"] == "wo": + return None + return self.values.get(offset, 0) + + def write(self, offset: int, size: int, value: int) -> bool: + spec = self._spec(offset, size) + if spec is None or spec["semantics"] == "ro": + return False + mask = (1 << (8 * size)) - 1 + value &= mask + sem = spec["semantics"] + if sem == "w1c": + self.values[offset] = self.values.get(offset, 0) & ~value & mask + elif sem == "set": + self.values[offset] = (self.values.get(offset, 0) | value) & mask + elif sem == "clear": + self.values[offset] = (self.values.get(offset, 0) & ~value) & mask + else: + self.values[offset] = value + return True + + def state(self) -> dict: + return {"values": {str(k): v for k, v in sorted(self.values.items())}, + "declared": sorted(self.registers)} + + def load_state(self, data: dict) -> None: + values = {int(k): int(v) for k, v in data.get("values", {}).items()} + self.values = {off: values.get(off, spec["reset"]) + for off, spec in self.registers.items()} -- cgit v1.2.3