summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md
diff options
context:
space:
mode:
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md')
-rw-r--r--debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md187
1 files changed, 187 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md b/debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md
new file mode 100644
index 0000000..018e07c
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/docs/32-GSP-CYCLE-MODEL.md
@@ -0,0 +1,187 @@
+# 32 — GSP cycle model (increment 0, in development)
+
+> **Status: in development (Phase 1.5, work package WP1.5.1 increment 0).**
+> This page describes a table-driven **modeled** cycle count added to the
+> native reference core (`sim/`) and a bounded, deterministic "cycle-0"
+> profile of the real 570.144 GSP firmware. It makes **no silicon timing,
+> performance, latency or accuracy claim**: the numbers are modeled defaults
+> under an explicit table, not measurements. The simulator's fidelity
+> statement is unchanged — L0 (instruction semantics) and L1 (memory
+> behaviour) are modelled; **L2 (time/concurrency) is not** (`06-ACCURACY.md`).
+> Development-only: nothing here authorises GPU hardware, kernel modules,
+> mdev or guest access.
+
+## 1. Purpose
+
+The native simulator reports virtual time as an instruction count (`insns`).
+That is enough for functional debugging but not for comparing instruction
+mixes, for calibration-table work, or for a first, honest cycle-shaped
+artifact from a real firmware run. Increment 0 adds:
+
+* `sim/cycles.py` — an isolated, per-instruction-class latency table with a
+ deterministic cost function;
+* a `cycles` counter on `sim.machine.Machine`, advanced by that table
+ alongside the existing instruction count;
+* `sim/gsp_profile.py` — a bounded, read-only run of the real
+ `firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin` that records a normal
+ `greeneye-session/1` directory with the modeled cycle totals;
+* `tests/test_sim_cycles.py`.
+
+Everything is stdlib-only Python 3.10+, offline, and read-only with respect to
+the firmware image.
+
+## 2. The model
+
+`sim/cycles.CycleModel` is a plain Python table. All defaults are **modeled**
+from public, generic in-order RISC-V pipeline assumptions — one cycle for
+plain ALU work, conservative multi-cycle M-extension costs, a fixed extra
+latency for a completed memory access — and are deliberately *not* derived
+from the GSP core, from silicon or from vendor data.
+
+| Class | Default | Notes |
+|---|---|---|
+| ALU / shift / `lui` / `auipc` / op-imm | 1 | add, sub, logical, compare |
+| branch | 1 | taken/not-taken penalty deliberately not modelled |
+| `jal` / `jalr` | 1 | |
+| `mul` / `mulh` / `mulhsu` / `mulhu` | 3 | conservative |
+| `div` / `divu` / `rem` / `remu` | 20 | conservative, data-independent |
+| load / store | 1 | plus a completed-access latency (below) |
+| AMO (`lr`/`sc`/`amo*`) | 2 | plus one completed-access latency |
+| CSR | 2 | |
+| trap (`ecall`/`ebreak`/`mret`) | 3 | |
+| `fence` / `fence.i` | 1 | no ordering model (single hart) |
+| illegal | 1 | execution stops immediately |
+
+Memory latency is a **parameter**, not a cache model:
+
+| Parameter | Default | Meaning |
+|---|---|---|
+| `memory_latency` | 3 | extra cycles when a RAM access completes |
+| `mmio_latency` | 12 | extra cycles when an unmodelled-MMIO access completes |
+
+The cost of one instruction is `instruction_cost(kind, sub)`; a completed
+load/store/AMO adds `memory_cost(is_mmio)` on top. Cost depends only on the
+decoded instruction class (`sim/decode.py` kind/sub) and the access region:
+no host clock, no entropy, no caches, no hazards. `CycleModel.describe()`
+emits the full table for session metadata.
+
+## 3. Machine integration
+
+`sim.machine.Machine` keeps its previous behaviour exactly; cycles are
+additive:
+
+```python
+from sim.machine import Machine
+
+m = Machine() # DEFAULT_MODEL active
+m.run(10_000)
+m.insns # virtual time (unchanged semantics)
+m.cycles # modeled cycles, advanced by the table
+m.cycle_model.name # "rv64imac-modeled/1"
+
+off = Machine(cycle_model=False) # cycles stays 0; disabling path for A/B
+slow = Machine(cycle_model=CycleModel(memory_latency=9))
+```
+
+`greeneye.sim_backend.launch_native(..., cycle_model=...)` threads the choice
+through the Session API (`None` = default table, `False` = off, or an
+instance). The counter increments for the instruction the machine stops on
+under a watchpoint/breakpoint, mirroring how `insns` counts it; the memory
+latency is only added when the access actually completes. Determinism is by
+construction: two identical runs produce identical instruction and cycle
+totals (tested).
+
+Measured overhead on this host (CPython 3.12, 200k instructions of the real
+image, best of three): ~0.073 s with accounting disabled vs ~0.082 s enabled
+(~12%); disabled runs are byte-for-byte the pre-increment behaviour.
+
+## 4. The cycle-0 GSP profile
+
+```bash
+# bounded, deterministic, read-only; writes a session under dumps/
+python3 -m sim.gsp_profile --instructions 200000
+
+# explicit session directory and machine-readable result
+python3 -m sim.gsp_profile --record dumps/gsp-cycle0 --json
+
+# start from a harvested first-touch map and keep what the run learned
+python3 -m sim.gsp_profile --device-map dumps/<probe>/device-map.json --learn --learn-out /tmp/map.json
+
+# image absent (e.g. LFS not fetched): exits 2 with a skip reason, no session
+python3 -m sim.gsp_profile --image /nonexistent.bin
+```
+
+The profile mirrors the established device-map/probe path: the ELF's PT_LOAD
+plan is relocated by `bias=0x80000000` (`greeneye/elf.py`), RAM is sized to
+cover the image as `greeneye/device_map.py` computes it, and all unmodelled
+accesses are served leniently (zero or the mapped value) through a
+`greeneye-device-map/1`. The instruction budget is exact, not wall-clock:
+`Machine.run(budget)` is called directly, so the run is deterministic.
+
+Session metadata (`session.json`) and a `gsp_cycle_profile` event carry:
+`firmware_sha256`, `bias`, `instructions_executed`, `cycles`,
+`cycle_model`, `cycle_model_table`, `cycle_fidelity`, `stop_reason`/`stop_pc`
+(both relocated and firmware-space), `mmio_unknown` and the first unknown
+MMIO access.
+
+**Observed output** (this tree, 2026-10-03; sha256
+`2d1bb5c6…c3ceea`, budget 200 000):
+
+```
+instructions: 200000
+cycles (modeled): 200012
+stop: budget pc=0x84009070 (fw 0x4009070)
+unknown MMIO accesses: 1
+first unknown MMIO: pc=0x84009014 addr=0x2000000000000a00 size=4 rw=r
+```
+
+This is a bounded lenient first-touch profile, **not a boot**: it reproduces
+the documented QEMU probe first-touch address and continues under the modeled
+lenient policy for the budget. The stop PC is a budget sample inside the
+firmware's early path, not a milestone.
+
+## 5. What is not claimed
+
+* No silicon timing, latency, throughput, frequency or pipeline claim; the
+ table is a modeled default and says so in code, metadata and reports
+ (`sim/cycles.py::NOTE`, `CYCLE_FIDELITY`).
+* No cache/memory-hierarchy model: `memory_latency`/`mmio_latency` are fixed
+ parameters, not simulated caches or DRAM.
+* No device model: L3 remains absent (`06-ACCURACY.md`); the profile runs
+ under lenient MMIO, so its control flow after the first unknown access is
+ conditioned on that policy, not on device behaviour.
+* No accuracy metric may be computed from this increment alone. Calibration
+ (`RISC-V-GSP-RM-DEBUGGER-ROADMAP.md`, `16-CUSTOM-SIMULATOR.md`) still
+ requires sourced latency tables and, for any product-facing claim,
+ supervised physical confirmation.
+
+## 6. Tests
+
+`tests/test_sim_cycles.py` (21 tests, all offline):
+
+* table sanity (every decoded kind has a positive cost; ALU/branch/jump unit
+ cost; M-extension ordering; memory latency is a parameter; labeling);
+* counter arithmetic on hand-assembled programs (RAM vs MMIO latency);
+* disabling the model leaves `cycles` at 0 and changes no execution state;
+* determinism double-runs at machine and profile level;
+* the bundled demo executes identically with and without the model;
+* real-image bounded profile: first touch matches the documented probe
+ address, session metadata carries the cycle totals, two runs are identical;
+* absent image skips cleanly.
+
+## 7. Next steps
+
+1. Device model (WP1.5.2): falcon/SEC2 windows, CSB/TRANSCOM, WPR2/FWSEC,
+ PTIMER, IRQ routing — the run then stops modelling MMIO leniently.
+2. Boot shims with recorded assumptions (WP1.5.3) so the profile can report a
+ real milestone instead of a budget sample.
+3. Sourced instruction/access latency tables and a documented calibration
+ metric (`06-ACCURACY.md`, `16-CUSTOM-SIMULATOR.md`) before any
+ timing-shaped statement; per-MCU cycle domains come with
+ WP1.5.4/WP1.5.5.
+4. Additive `cycle` event class in the session schema (roadmap V2, "formats
+ and versioning") once the event vocabulary is reviewed.
+
+The increment is deliberately a table and a counter: every later step can
+replace defaults without touching the execution loop (the model is passed in)
+or the session format (metadata is additive).