summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/sim/devices/priscv.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-03 14:05:38 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-03 14:05:38 -0400
commitcc79b478843f0230fe6aa8ecd822de7ba71c891e (patch)
tree5de760ddec4e45cc23d39ce7502635f5c0711217 /debug/risc-v-gsp-rm-vm/sim/devices/priscv.py
parent40351167dd209012ab485e6164ce94f0b8965422 (diff)
downloadopen-iov-cc79b478843f0230fe6aa8ecd822de7ba71c891e.tar.gz
open-iov-cc79b478843f0230fe6aa8ecd822de7ba71c891e.zip
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
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/sim/devices/priscv.py')
-rw-r--r--debug/risc-v-gsp-rm-vm/sim/devices/priscv.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/sim/devices/priscv.py b/debug/risc-v-gsp-rm-vm/sim/devices/priscv.py
new file mode 100644
index 0000000..62a8fea
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/sim/devices/priscv.py
@@ -0,0 +1,113 @@
+"""RISC-V local (PRISCV) register block.
+
+Evidence kind: **hardware register/field header + observed access pattern.**
+
+Reached through the PRIV aperture at ``PRIV + 0x111000`` and through the libos
+kernel's private mapping at ``0x3_0000_1000`` (the firmware reads the trace
+and error-status registers there during boot). Modelled registers:
+
+================================ ====== ===== ==============================
+register offset access semantics
+================================ ====== ===== ==============================
+``RISCV_IRQMSET`` 0x2ac W ``irq_mask |= value``
+``RISCV_IRQMCLR`` 0x2b0 W ``irq_mask &= ~value``
+``RISCV_IRQMASK`` 0x2b4 R ``irq_mask``
+``RISCV_IRQDEST`` 0x2b8 RW storage
+``RISCV_IRQTYPE`` 0x2bc RW storage
+``RISCV_TRACECTL`` 0x344 RW storage
+``RISCV_TRACE_RDIDX`` 0x348 RW storage
+``RISCV_TRACE_WTIDX`` 0x34c RW storage
+``RISCV_PRIV_ERR_STAT`` 0x360 RW storage
+``RISCV_HUB_ERR_STAT`` 0x36c RW storage
+================================ ====== ===== ==============================
+
+The IRQ mask semantics (set/clear/read) follow the header access types and the
+observed boot reads; core interrupt *delivery* (mtvec/mip) is not part of this
+device and remains unmodelled (documented unknown).
+"""
+from __future__ import annotations
+
+from .base import Device
+
+IRQMSET = 0x2AC
+IRQMCLR = 0x2B0
+IRQMASK = 0x2B4
+IRQDEST = 0x2B8
+IRQTYPE = 0x2BC
+TRACECTL = 0x344
+TRACE_RDIDX = 0x348
+TRACE_WTIDX = 0x34C
+PRIV_ERR_STAT = 0x360
+PRIV_ERR_INFO = 0x364
+PRIV_ERR_ADDR = 0x368
+HUB_ERR_STAT = 0x36C
+
+_RW = {IRQDEST, IRQTYPE, TRACECTL, TRACE_RDIDX, TRACE_WTIDX,
+ PRIV_ERR_STAT, HUB_ERR_STAT}
+#: Read-only error capture registers (header R-I4R); the boot panic path
+#: reads them after a trap (observed reads at PC 0x40106BC).
+_RO = {PRIV_ERR_INFO, PRIV_ERR_ADDR}
+
+
+class PriscvBlock(Device):
+ """RISC-V-local control/trace/error registers."""
+
+ name = "priscv"
+
+ def __init__(self, *, base: int = 0, size: int = 0x1000):
+ super().__init__(base=base, size=size)
+ self.reset()
+
+ def reset(self) -> None:
+ self.irq_mask = 0
+ self.regs: dict[int, int] = {off: 0 for off in _RW}
+ self.error: dict[int, int] = {off: 0 for off in _RO}
+
+ def read(self, offset: int, size: int) -> int | None:
+ if size != 4:
+ return None
+ if offset == IRQMASK:
+ return self.irq_mask
+ if offset in self.regs:
+ return self.regs[offset]
+ if offset in self.error:
+ return self.error[offset]
+ return None
+
+ def write(self, offset: int, size: int, value: int) -> bool:
+ if size != 4:
+ return False
+ value &= 0xFFFFFFFF
+ if offset == IRQMSET:
+ self.irq_mask = (self.irq_mask | value) & 0xFFFFFFFF
+ return True
+ if offset == IRQMCLR:
+ self.irq_mask = (self.irq_mask & ~value) & 0xFFFFFFFF
+ return True
+ if offset == IRQMASK:
+ return False # read-only
+ if offset in self.regs:
+ self.regs[offset] = value
+ return True
+ return False
+
+ def peek(self, offset: int, size: int) -> int | None:
+ if size != 4:
+ return None
+ if offset == IRQMASK:
+ return self.irq_mask
+ if offset in self.error:
+ return self.error[offset]
+ return self.regs.get(offset)
+
+ def state(self) -> dict:
+ return {"irq_mask": self.irq_mask,
+ "regs": {str(k): v for k, v in sorted(self.regs.items())},
+ "error": {str(k): v for k, v in sorted(self.error.items())}}
+
+ def load_state(self, data: dict) -> None:
+ self.irq_mask = int(data.get("irq_mask", 0))
+ regs = {int(k): int(v) for k, v in data.get("regs", {}).items()}
+ self.regs = {off: regs.get(off, 0) for off in _RW}
+ err = {int(k): int(v) for k, v in data.get("error", {}).items()}
+ self.error = {off: err.get(off, 0) for off in _RO}