Skip to main content

celox_runtime/
backend.rs

1use std::sync::Arc;
2
3use num_bigint::BigUint;
4
5pub use crate::SimulatorErrorCode;
6use crate::{AbsoluteAddr, MemoryLayout, RuntimeEventBuffer, SignalRef};
7
8/// Marker trait for backend-specific event handles.
9///
10/// An event handle is an opaque reference to a compiled clock or
11/// async-reset trigger. It is resolved once via
12/// [`SimBackend::resolve_event`] and then passed to tick/eval methods
13/// for zero-cost dispatch.
14pub trait EventHandle: Copy + std::fmt::Debug {
15    /// Numeric event identifier used for scheduling.
16    fn id(&self) -> usize;
17
18    /// The absolute address of the signal this event is bound to.
19    fn addr(&self) -> AbsoluteAddr;
20}
21
22/// Abstraction over different simulation backends (JIT, WASM, etc.).
23///
24/// `Simulator<B>` is generic over this trait so that the same high-level
25/// API works with any backend. `JitBackend` is the default.
26pub trait SimBackend {
27    /// The event handle type produced by this backend.
28    type Event: EventHandle;
29
30    // ── evaluation ──────────────────────────────────────────────
31    fn eval_comb(&mut self) -> Result<(), SimulatorErrorCode>;
32
33    /// Evaluate and apply a flip-flop domain for the given event.
34    fn eval_apply_ff_at(&mut self, event: Self::Event) -> Result<(), SimulatorErrorCode>;
35
36    /// Evaluate combinational logic and then evaluate/apply one flip-flop
37    /// domain. Backends may override this to compile the two phases as one
38    /// function; the default preserves the same ordering with two calls.
39    fn eval_comb_apply_ff_at(&mut self, event: Self::Event) -> Result<(), SimulatorErrorCode> {
40        self.eval_comb()?;
41        self.eval_apply_ff_at(event)
42    }
43
44    /// Execute up to `count` identical fused ticks. The returned count is the
45    /// number of iterations completed before a runtime event or error forced a
46    /// return to the host. Backends without an in-function loop execute one
47    /// iteration so the caller can preserve per-tick observation semantics.
48    fn eval_comb_apply_ff_many_at(
49        &mut self,
50        event: Self::Event,
51        count: u64,
52    ) -> (u64, Result<(), SimulatorErrorCode>) {
53        if count == 0 {
54            return (0, Ok(()));
55        }
56        (1, self.eval_comb_apply_ff_at(event))
57    }
58
59    /// Evaluate FF domain without applying (for cascaded clocks).
60    fn eval_only_ff_at(&mut self, event: Self::Event) -> Result<(), SimulatorErrorCode>;
61
62    /// Apply (commit) an already-evaluated FF domain.
63    fn apply_ff_at(&mut self, event: Self::Event) -> Result<(), SimulatorErrorCode>;
64
65    // ── signal access ───────────────────────────────────────────
66    fn resolve_signal(&self, addr: &AbsoluteAddr) -> SignalRef;
67    fn resolve_event(&self, addr: &AbsoluteAddr) -> Self::Event;
68    fn resolve_event_opt(&self, addr: &AbsoluteAddr) -> Option<Self::Event>;
69    fn resolve_eval_only_event(&self, addr: &AbsoluteAddr) -> Option<Self::Event>;
70    fn resolve_apply_event(&self, addr: &AbsoluteAddr) -> Option<Self::Event>;
71
72    // ── get / set ───────────────────────────────────────────────
73    fn set<T: Copy>(&mut self, signal: SignalRef, val: T);
74    fn set_wide(&mut self, signal: SignalRef, val: BigUint);
75    fn set_four_state(&mut self, signal: SignalRef, val: BigUint, mask: BigUint);
76    fn get(&self, signal: SignalRef) -> BigUint;
77    fn get_as<T: Default + Copy>(&self, signal: SignalRef) -> T;
78    fn get_four_state(&self, signal: SignalRef) -> (BigUint, BigUint);
79
80    // ── memory / layout ─────────────────────────────────────────
81    fn memory_as_ptr(&self) -> (*const u8, usize);
82    fn memory_as_mut_ptr(&mut self) -> (*mut u8, usize);
83    fn runtime_event_buffer_as_ptr(&self) -> (*const u8, usize);
84    fn runtime_event_buffer(&self) -> Option<Arc<RuntimeEventBuffer>> {
85        None
86    }
87    fn set_comb_capture_event_enabled(&mut self, _active_sites: &[bool]) {}
88    fn stable_region_size(&self) -> usize;
89    fn layout(&self) -> &MemoryLayout;
90
91    // ── event enumeration ───────────────────────────────────────
92    fn id_to_addr_slice(&self) -> &[AbsoluteAddr];
93    fn id_to_event_slice(&self) -> &[Self::Event];
94    fn num_events(&self) -> usize;
95
96    // ── trigger bits (for Simulation edge detection) ────────────
97    fn clear_triggered_bits(&mut self);
98    fn mark_triggered_bit(&mut self, id: usize);
99    fn get_triggered_bits(&self) -> bit_set::BitSet;
100}