diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-03 14:05:38 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-03 14:05:38 -0400 |
| commit | 32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5 (patch) | |
| tree | d1cab6bcc35e461610cd5dfcf3f51ba679a576fc /debug/risc-v-gsp-rm-vm/sim/devices/timer.py | |
| parent | fa71f1b53b524e5f6c6c1fbff1088d610b9f3236 (diff) | |
| download | open-iov-32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5.tar.gz open-iov-32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5.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/timer.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/sim/devices/timer.py | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/sim/devices/timer.py b/debug/risc-v-gsp-rm-vm/sim/devices/timer.py new file mode 100644 index 0000000..c57ee06 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/sim/devices/timer.py @@ -0,0 +1,86 @@ +"""PTIMER block (modeled virtual time; not a silicon timing claim). + +Evidence kind: **hardware register/field header** (offsets and field layout) +plus a *modeled* time source. The firmware has not yet been observed reading +this block in the 570.144 boot runs (the observed time-like reads were on +falcon MAILBOX1); the device is therefore opt-in: it is registered only when +a profile declares a ``timer`` section, and a section with +``"enabled": false`` is skipped. Its values are explicitly labelled +*modeled*. + +Header facts used: + +* ``NV_PTIMER`` block base ``0x9000`` in the register aperture. +* ``NV_PTIMER_TIME_0`` at aperture offset ``0x9400``: nanoseconds bits + ``31:5``. +* ``NV_PTIMER_TIME_1`` at aperture offset ``0x9410``: nanoseconds bits + ``28:0``. +* Reads of TIME_0 latch TIME_1 (paired read), as on the hardware register + pair; the simulator derives nanoseconds from the machine's instruction + count times the profile's ``ns_per_insn`` (default 1.0, i.e. 1 ns/insn -- + a placeholder, not calibrated). + +Register offsets below are **relative to the block window base** the profile +declares (``PRIV + 0x9000``), i.e. aperture offset minus ``PTIMER_BASE``: +``0x9400 - 0x9000 = 0x400``. Using the aperture-absolute numbers here would +place the registers outside the declared window and serve nothing. +""" +from __future__ import annotations + +from .base import Device + +PTIMER_BASE = 0x9000 +#: Block-relative offsets of NV_PTIMER_TIME_0/1 (aperture 0x9400/0x9410). +TIME_0 = 0x400 +TIME_1 = 0x410 + + +class PtimerBlock(Device): + """Two-register nanosecond timer with a modeled tick source.""" + + name = "timer" + + def __init__(self, *, base: int = 0, size: int = 0x1000, + ns_per_insn: float = 1.0, clock=None): + super().__init__(base=base, size=size) + self.ns_per_insn = float(ns_per_insn) + self.clock = clock # callable returning virtual instruction count + self._latch = 0 + self.reads = 0 + + def _now_ns(self) -> int: + insns = self.clock() if self.clock is not None else 0 + return int(insns * self.ns_per_insn) & 0xFFFFFFFFFFFFFFFF + + def read(self, offset: int, size: int) -> int | None: + if size != 4: + return None + if offset == TIME_0: + self._latch = self._now_ns() + self.reads += 1 + return (self._latch >> 5) & 0xFFFFFFFF # NSEC field 31:5 + if offset == TIME_1: + self.reads += 1 + return self._latch & 0x1FFFFFFF # NSEC field 28:0 + return None + + def peek(self, offset: int, size: int) -> int | None: + if size != 4: + return None + if offset == TIME_0: + return (self._now_ns() >> 5) & 0xFFFFFFFF + if offset == TIME_1: + return self._now_ns() & 0x1FFFFFFF + return None + + def write(self, offset: int, size: int, value: int) -> bool: + return False + + def state(self) -> dict: + return {"ns_per_insn": self.ns_per_insn, "latch": self._latch, + "reads": self.reads} + + def load_state(self, data: dict) -> None: + self.ns_per_insn = float(data.get("ns_per_insn", self.ns_per_insn)) + self._latch = int(data.get("latch", 0)) + self.reads = int(data.get("reads", 0)) |
