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
impl Engine
Sourcepub fn new(arena: Box<dyn SignalAccess>, io: Box<dyn IoSink>) -> Self
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.
Sourcepub fn set_registration_scope(&mut self, scope: Option<u32>)
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.
Sourcepub fn set_registration_static_initializer(&mut self, on: bool)
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.
Sourcepub fn set_timestep_end_hook(&mut self, hook: Box<dyn FnMut(SchedTime)>)
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.
Sourcepub fn configure_preponed_ring(
&mut self,
depth: usize,
source: impl Fn() -> ArenaSnapshot + 'static,
)
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.
Sourcepub fn max_delta_iterations_in_a_timestep(&self) -> u32
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.
Sourcepub fn controller_kind(&self) -> &'static str
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.
Sourcepub fn current_region(&self) -> Region
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”).
Sourcepub fn advance_nba_region(&mut self) -> StepResult
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.
Sourcepub fn set_host(&mut self, host: Box<dyn Host>)
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).
Sourcepub fn push_region_callback(
&self,
at: SchedTime,
region: Region,
cb: Box<dyn RegionCallback>,
) -> Result<(), RegionCallbackRegionError>
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
impl Engine
Sourcepub fn mark_program_initial(&mut self, id: ProcessId)
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.
pub fn register_reactive_process( &mut self, proc: Box<dyn CompiledProcess>, kind: ProcessKind, sensitivity: Option<StaticSensitivity>, region_id: u32, ) -> ProcessId
Sourcepub fn register_procedure(
&mut self,
proc: Box<dyn CompiledProcess>,
kind: ProcessKind,
sensitivity: Option<StaticSensitivity>,
region_id: u32,
) -> ProcessId
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.
Sourcepub fn narrow_static_sensitivity(
&mut self,
proc: ProcessId,
cell: StateCellId,
windows: &[(u32, u32)],
)
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
impl SchedulerControl for Engine
Source§fn register_process(
&mut self,
proc: Box<dyn CompiledProcess>,
kind: ProcessKind,
sensitivity: Option<StaticSensitivity>,
region_id: u32,
) -> ProcessId
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
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
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.