Skip to main content

Engine

Struct Engine 

Source
pub struct Engine { /* private fields */ }
Expand description

The first type in the crate that assembles every earlier task’s pieces together.

Implementations§

Source§

impl Engine

Source

pub fn new(arena: Box<dyn SignalAccess>, io: Box<dyn IoSink>) -> Self

sched borrows the SignalAccess/IoSink contracts but does not implement them this wave — dependency-injecting both is what lets Engine be genuinely constructible and testable without this crate depending on a STATE/RUNTIME implementation. controller starts as SequentialController::default_boxed() (Task 3), overridable via set_determinism_controller.

Source

pub fn set_registration_scope(&mut self, scope: Option<u32>)

Classes plan Task 14 (LRM 18.14.1): names the instance scope whose initialization RNG seeds every process registered from now on (None, the default, seeds nothing: the process draws from the unseeded default like any process with no known parent). The production caller sets it around the user’s procedural blocks only, so the infrastructure processes registered elsewhere (net resolvers, samplers, …) never advance an instance’s initialization RNG and so never shift the seed any user process gets.

Source

pub fn set_registration_static_initializer(&mut self, on: bool)

While set (and a Self::set_registration_scope scope is active), a process registered runs a static declaration initializer (int x = f();, C h = new;) rather than being a thread of its own: LRM 18.14.1 gives such code no thread, so it draws from the instance’s initialization RNG directly ([process_rng::alias_init]) instead of being seeded from it.

Source

pub fn set_timestep_end_hook(&mut self, hook: Box<dyn FnMut(SchedTime)>)

Installs the end-of-timestep hook (see the field’s doc comment), replacing any previous one.

Source

pub fn configure_preponed_ring( &mut self, depth: usize, source: impl Fn() -> ArenaSnapshot + 'static, )

NEW (sva T1, LRM 16.5.1/16.5.2). Installs a Preponed-region snapshot ring of the given depth (state::snapshot::SnapshotRing’s own doc comment), sourced by calling source once per time step. Replaces any previously configured ring. Never called at all for a design with no assertion/clocking-block/$past site – [Self:: push_preponed_snapshot] stays a no-op (no allocation, source never invoked) until this is.

Source

pub fn max_delta_iterations_in_a_timestep(&self) -> u32

NEW (Task 21, ledger SC-007). The maximum DeltaGuard::count this Engine has observed at the settled end of any one timestep’s inner Active/Inactive/NBA convergence loop, across its whole run so far — a high-water mark, not the current timestep’s own count (which is always 0 immediately after run_until returns, since guard. reset() runs every timestep). Existence-proof surface for SC-007’s “region-stratified delta-cycle convergence” acceptance: a caller can assert this stayed low for a design that should settle in a handful of passes, catching an accidental unbounded-oscillation regression well before it would ever hit DEFAULT_MAX_DELTA_ITERATIONS.

Source

pub fn controller_kind(&self) -> &'static str

Testability getter (DT-007’s “selected by default when no other controller is configured”, made externally observable): see DeterminismController::kind.

Source

pub fn current_region(&self) -> Region

NEW (A2-part2 Task 5, ledger CG-162): exposes the region Self::step_region is about to process next – needed so the ABI’s sim_eval_region(requested_region, ..) (vj-runtime:: abi_entry) can single-step exactly up to (but never past) requested_region, and, for Region::Nba specifically, stop there WITHOUT calling step_region/Self::advance_nba_region at all: RHS evaluation for any pending NBA writes already happened during the prior Active/Inactive dispatch passes (nba_enqueue only ever stages into NbaLog, never touches the arena – see EngineOps::stage_nba), so observing “we have arrived at the Nba boundary” is genuinely a read-only query, and Self::advance_nba_region stays the one, separate, explicit call that applies the staged log (CG-162’s “never collapsed into one call”).

Source

pub fn advance_nba_region(&mut self) -> StepResult

NEW (A2-part2 Task 5, ledger CG-162): the LRM’s NBA update-APPLICATION half, extracted verbatim from step_region’s own Region::Nba arm (a pure refactor – step_region’s own observable behavior, for every existing caller including debugger/VPI single-stepping, is unchanged bit-for-bit) so it can also be called directly as its own, separately-named operation. The ABI’s sim_commit_nba entry point (vj-runtime::abi_entry) needs exactly this, decoupled from sim_eval_region(Nba) (see Self::current_region’s own doc comment for that half) – ARCHITECTURE §5’s “sim_commit_nba kept distinct from eval_region(Nba) to mirror the LRM’s RHS-eval vs update-apply split,” never collapsed into one call.

Source

pub fn set_host(&mut self, host: Box<dyn Host>)

Advances the wheel to tick, dispatching every popped TimerEntry per its own TimerAction (SC-069): a Resume entry pushes onto its target region’s queue exactly as before this task; a TriggerEvent entry is fanned out through [EngineNotifySink::notify_change] – the same path an ordinary committed write already uses – with EdgeKind::None (the sentinel SensitivityTable::matches already treats as “any change”/a trigger pulse, sensitivity.rs’s own doc comment). Then advances self.now.

Triggers are collected and fired only after every Resume entry has already been pushed and self.now updated: notify_change reads self.now (via the EngineNotifySink it constructs) for the PendingActivations it enqueues, so a trigger fired at the new tick must see that tick as self.now, not the pre-advance value. The earliest tick with anything scheduled: a wheel entry or a delayed nonblocking write. Installs the embedder’s scheduling hooks (super::host).

Source

pub fn push_region_callback( &self, at: SchedTime, region: Region, cb: Box<dyn RegionCallback>, ) -> Result<(), RegionCallbackRegionError>

NEW (Task 4, ledger SC-090/SC-123). Pushes cb onto Self::region_callbacks to fire once region is next drained (via Self::drain_region_callbacks) with self.now >= at. Not #[cfg(test)]-gated: EngineOps::register_region_callback (the SchedulerOps trait method’s one production implementation) is a thin forward to this, and this module’s own test setup calls it directly for callbacks registered before run_until starts (where no SchedulerOps/dispatched-process context exists yet).

Review fix (Task 4 r1): exhaustive match region, mirroring RegionQueues::push’s own established Result convention: Reactive/Postponed are the only two regions Self::drain_region_callbacks ever drains (see that method’s own doc comment), so only those two push and return Ok(()); Active/Inactive/Nba return Err(RegionCallbackRegionError::NotDrained(region)) instead of silently accepting a registration that would sit in region_callbacks forever and never fire. sva T1/T2: Preponed was added to the rejecting side (T1); Observed was added to the ACCEPTING side (T2) once drain_region_callbacks grew a real caller for it – see the match’s own per-arm comments below.

Source§

impl Engine

Source

pub fn mark_program_initial(&mut self, id: ProcessId)

Registers a process that runs in the Reactive region (LRM 17.7.3): a checker’s procedures and continuous assignments “are scheduled in the Reactive region, similarly to programs”. Its start activation and every wake-up (a static or dynamic sensitivity match) are queued in Reactive, which the time step drains after Active, Inactive, NBA and the Observed region have settled and re-enters the delta loop from when it leaves work behind (see run_until). Otherwise identical to SchedulerControl::register_process. Marks id (just registered) as a program block’s initial thread (LRM 24.3: “the simulation ends implicitly when all the program threads end”). Its fork descendants inherit the mark.

Source

pub fn register_reactive_process( &mut self, proc: Box<dyn CompiledProcess>, kind: ProcessKind, sensitivity: Option<StaticSensitivity>, region_id: u32, ) -> ProcessId

Source

pub fn register_procedure( &mut self, proc: Box<dyn CompiledProcess>, kind: ProcessKind, sensitivity: Option<StaticSensitivity>, region_id: u32, ) -> ProcessId

SchedulerControl::register_process for a user-written procedure (initial/always*): an always_comb/always_latch starts after every other process of the time-zero Active region has started, LRM 1800-2023 9.2.2.2 (“automatically triggered once at time zero, after all initial and always procedures have been started”). A continuous assignment (also an AlwaysComb kernel) keeps register_process: it starts in registration order like any Active process.

Source

pub fn narrow_static_sensitivity( &mut self, proc: ProcessId, cell: StateCellId, windows: &[(u32, u32)], )

Narrows proc’s always_comb/always_latch sensitivity on cell to the constant bit windows it reads (LRM 9.2.2.2.1, longest static prefix); see SensitivityTable::narrow_static.

Trait Implementations§

Source§

impl SchedulerControl for Engine

Source§

fn register_process( &mut self, proc: Box<dyn CompiledProcess>, kind: ProcessKind, sensitivity: Option<StaticSensitivity>, region_id: u32, ) -> ProcessId

See this module’s doc comment, deviation 2, for the additional kind-based branching beyond the plan’s literal two statements.

Source§

fn run_until(&mut self, deadline: Option<SchedTime>) -> RunResult

scheduler.md §1’s pseudocode, concretely: per timestep, an inner Active/Inactive/NBA delta-convergence loop (guarded by DeltaGuard, SC-079/SC-080), then Reactive/Postponed drained once each, finish_requested checked once per timestep (SC-075 — see this module’s doc comment, deviation 4), then the wheel is asked for the next tick.

Source§

fn step_region(&mut self) -> StepResult

Single-steps through the 5-region cycle, one call per region (see this module’s doc comment, deviation 3, for scope): Active -> Inactive -> Nba -> (back to Active if not yet settled, else) Reactive -> Postponed -> (wheel advance, back to Active, or Blocked if the wheel is empty too). A debugger-mock harness driving this repeatedly observes only committed state between calls: every write reaching STATE goes through commit_blocking_write/commit_nba synchronously, inside this call, never buffered across calls.

Source§

fn run_finals(&mut self)

Source§

fn now(&self) -> SchedTime

Source§

fn set_determinism_controller(&mut self, ctrl: Box<dyn DeterminismController>)

Auto Trait Implementations§

§

impl !Freeze for Engine

§

impl !RefUnwindSafe for Engine

§

impl !Send for Engine

§

impl !Sync for Engine

§

impl !UnwindSafe for Engine

§

impl Unpin for Engine

§

impl UnsafeUnpin for Engine

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V