pub struct System {
pub cpu: Cpu,
pub bus: Bus,
/* private fields */
}Expand description
Owns the run loop and ties the CPU to the Bus on one timeline.
Determinism contract: same seed + ROM + input ⇒ bit-identical A/V (ADR 0004).
Fields§
§cpu: CpuThe CPU.
bus: BusThe Bus — owns everything else mutable (RDRAM / RSP / RDP / AI / cart / controllers / RCP registers).
Implementations§
Source§impl System
impl System
Sourcepub fn new(seed: u64) -> Self
pub fn new(seed: u64) -> Self
Power on with a determinism seed (drives the per-domain phase alignment).
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Reset (warm). Re-derives the SAME phase alignment from the retained seed so a reset mid-run stays deterministic.
Sourcepub const fn master_ticks(&self) -> u64
pub const fn master_ticks(&self) -> u64
Master ticks elapsed since power-on. The canonical time position.
Sourcepub const fn cpu_cycles(&self) -> u64
pub const fn cpu_cycles(&self) -> u64
The CPU’s position on the timeline, in PClocks. Derived, not stored.
This is a position, not a count of work done — with a nonzero seeded
phase it is nonzero before the CPU has stepped, which is correct and is
what the residue invariant pins. For work retired, use Cpu::retired.
Sourcepub const fn rcp_cycles(&self) -> u64
pub const fn rcp_cycles(&self) -> u64
The RCP’s position on the timeline, in MClocks. Derived, not stored.
Sourcepub const fn count_ticks(&self) -> u64
pub const fn count_ticks(&self) -> u64
The COP0 Count offset since power-on, at half PClock.
Not the architectural register: Count is guest-writable via MTC0, so
the real value is affine — epoch_value + (master_ticks - epoch_tick) / COUNT_DIVIDER, re-based on every write. The affine half lives in the CPU
(rustyn64_cpu::cop0, T-12-003) and is fed from here via tick_at; this
is the timeline half.
Sourcepub fn step_to_next_edge(&mut self) -> u64
pub fn step_to_next_edge(&mut self) -> u64
Advance to the next tick at which any domain is due, and step every domain due at that tick. Returns the tick landed on.
Edge-to-edge: the master tick is never iterated. Hot path — allocation-free.
Note the tick the machine currently sits on is never re-stepped, so tick 0 is a position rather than an executed edge. Only the intervals between ticks carry work, which is what keeps the residue invariant constant.
Sourcepub fn run_until(&mut self, target: u64)
pub fn run_until(&mut self, target: u64)
Run until master_ticks() == target, stepping every domain on every edge
in (now, target] — and not one past it.
Overshooting would make “how many CPU steps in N ticks” depend on where the edges happened to fall, which is exactly the kind of off-by-a-phase error the residue invariant is meant to make impossible.