pub struct TimingModel {
pub paths: Vec<PathEntry>,
pub timing_checks: Vec<CheckEntry>,
/* private fields */
}Expand description
The per-design, runtime-mutable timing-annotation table (§1.1).
Fields§
§paths: Vec<PathEntry>One per desugared PathEntry (Track A).
timing_checks: Vec<CheckEntry>One per CheckEntry (Track B).
Implementations§
Source§impl TimingModel
impl TimingModel
Sourcepub fn new() -> TimingModel
pub fn new() -> TimingModel
An empty table (no design has been seeded into it yet).
Sourcepub fn seed_specparams(&mut self, infos: &[(InstanceId, Symbol<'_>)])
pub fn seed_specparams(&mut self, infos: &[(InstanceId, Symbol<'_>)])
Seeds the specparam table from every Specparam member of each
(instance, body) pair in infos — the SAME per-instance
(InstanceId, Symbol) shape sv-sim-bin::primitives::plan’s own
bodies parameter already uses — via super::module_items (the
same discovery surface primitives.rs already walks). Specparam
is a direct module member, legal both inside and outside a specify
block (LRM 30.3). Stores each one’s frozen constant_value() — the
pre-SDF baseline a later $sdf_annotate LABEL annotation
(Task 28) overwrites in place through Self::set_specparam.
A specparam declared INSIDE a specify ... endspecify block (LRM
30.3’s own specify_item production lists specparam_declaration;
30.7.1’s PATHPULSE$ is only ever legal there) is not a direct
Specparam member of body the way a module-scope one is:
module_items deliberately leaves SpecifyBlock opaque (it only
recurses into GenerateBlock/GenerateBlockArray, per that
function’s own doc comment — dedup.rs/elaborate.rs/instance.rs/
primitives.rs all rely on that), so a specify-block specparam’s
real Specparam symbol is a child of the SpecifyBlock member
itself, never surfaced by the module_items walk above. This loop
therefore also looks inside every SpecifyBlock member it finds and
seeds any Specparam declared directly in it, one level deep (a
specify block cannot nest another one — 30.3 gives it no such
production — so one level is exhaustive).
Deviation from the plan’s own pseudocode signature: no &EvalSession
parameter. Symbol::constant_value() is documented as “a pure read
on a frozen design… never evaluates” (sv-lang’s own doc comment),
so no session is needed here — the plan carried one for symmetry
with specify_eval::eval_specparam_aware’s (which genuinely needs
one, for its general-constant-folding fallback), not because seeding
itself requires one.
Sourcepub fn specparam(
&self,
instance: InstanceId,
uid: &SymbolId,
) -> Option<&ConstantValue>
pub fn specparam( &self, instance: InstanceId, uid: &SymbolId, ) -> Option<&ConstantValue>
The specparam identified by (instance, uid)’s current value: the
pre-SDF baseline seed_specparams stored,
or whatever a later direct mutation ([set_specparam]
(Self::set_specparam) — $sdf_annotate, Task 28) has since
overwritten it with. A plain table lookup, needing no
EvalSession/live Design.
Sourcepub fn set_specparam(
&mut self,
instance: InstanceId,
uid: SymbolId,
value: ConstantValue,
)
pub fn set_specparam( &mut self, instance: InstanceId, uid: SymbolId, value: ConstantValue, )
Overwrites (or inserts) a specparam’s value directly — what Task 28’s
real SDF LABEL annotation calls, and what this task’s own unit
tests use to simulate it ahead of time. This task’s “mutation path”
acceptance criterion: no EvalSession/Design/Symbol anywhere in
this signature, only InstanceId/SymbolId/the plain, fully-owned
ConstantValue.
Sourcepub fn set_path_delays(
&mut self,
instance: InstanceId,
path_uid: &SymbolId,
delays: PathDelaySet,
)
pub fn set_path_delays( &mut self, instance: InstanceId, path_uid: &SymbolId, delays: PathDelaySet, )
Attaches delays to every desugared PathEntry that came from
the one TimingPath symbol identified by (instance, path_uid)
(LRM 30.4.6: several entries share one declaration, and all share
its one delay list) – sv-sim-bin’s own plan-time pass
(crate::specify::discover, right after calling Self::discover)
is the only caller; see PathEntry::delays’s own doc comment for
why evaluation lives there, not here. A no-op, never an error, if
nothing matches – Self::discover’s own loop already guarantees
that a path_uid it produced has at least one entry, so a caller
passing a path_uid it did not itself get from THIS SAME
TimingModel’s own Self::paths is a caller bug, not a runtime
condition this method needs to report.
Sourcepub fn set_path_pulse_limits(
&mut self,
instance: InstanceId,
path_uid: &SymbolId,
reject: u64,
error: u64,
)
pub fn set_path_pulse_limits( &mut self, instance: InstanceId, path_uid: &SymbolId, reject: u64, error: u64, )
Attaches a PATHPULSE$ (LRM 30.7.1) – reject and error, already
evaluated and tick-converted by the caller exactly like
Self::set_path_delays’s own delays (see that method for why
evaluation lives in sv-sim-bin) – to every desugared PathEntry
of the one TimingPath symbol (instance, path_uid); every
transition of each gets the same two values.
Implementation-defined choice: LRM 30.7.1 requires the error limit
to be at least the reject limit but does not say what a source that
writes (6, 2) means. Rather than reject a design over it, the error
limit is raised to the reject limit (error = max(error, reject)),
which makes the region between the two empty: a pulse is then either
cancelled or passed, never filtered to x.
Like Self::set_path_delays, a no-op if nothing matches.
Sourcepub fn apply_pulse_percent(&mut self, reject_pct: f64, error_pct: f64)
pub fn apply_pulse_percent(&mut self, reject_pct: f64, error_pct: f64)
Sets every path’s reject and error limit to reject_pct / error_pct percent of each
transition’s OWN delay (LRM 30.7.2, 32.7: the global invocation options), rounded to the
nearest tick, an error limit below the reject limit raised to it (the same
implementation-defined repair as Self::set_path_pulse_limits). 100.0 is exact (the
LRM default, limits equal to the delays). A PATHPULSE$ is more specific than this
option and must be applied AFTER it (Self::set_path_pulse_limits); like
Self::set_path_delays, which re-establishes the default this replaces, it must come
after the delays.
Sourcepub fn set_pulse_options(
&mut self,
style: Option<PulseStyle>,
showcancelled: Option<bool>,
)
pub fn set_pulse_options( &mut self, style: Option<PulseStyle>, showcancelled: Option<bool>, )
Sets the pulse style and showcancelled invocation options (LRM 30.7.4.1/30.7.4.2). An
option that is Some takes precedence over every specify block declaration of its axis
(the LRM’s own wording), so Self::discover applies it AFTER the declarations; one that
is None was not given and the declarations (then the built-in on-event /
noshowcancelled) decide. Must be called BEFORE Self::discover.
Sourcepub fn discover<'d>(
&mut self,
eval: &EvalSession<'d>,
infos: &[(InstanceId, Symbol<'d>)],
) -> Result<(), ElabError>
pub fn discover<'d>( &mut self, eval: &EvalSession<'d>, infos: &[(InstanceId, Symbol<'d>)], ) -> Result<(), ElabError>
Walks every (instance, body) pair’s SpecifyBlock members
(Task 3, docs/superpowers/plans/2026-10-03-sdf.md), appending one
PathEntry per desugared module path to Self::paths and one
CheckEntry per SystemTimingCheck to Self::timing_checks
([discover_check] decodes its arguments by kind and enforces the
clause’s compile-time restrictions as named errors, Task 13).
SpecifyBlock’s own member-kind match is exhaustive over LRM 30.3’s
specify_item production (specparam_declaration |
path_declaration | system_timing_check |
pulsestyle_declaration/showcancelled_declaration, i.e.
SymbolKind::{Specparam,TimingPath,SystemTimingCheck,PulseStyle}):
any other member kind is a named ElabError::UnsupportedConstruct,
never a silent skip, matching this crate’s own top-of-file
discipline. Specparam members are skipped here (already seeded by
Self::seed_specparams); PulseStyle members (Task 11:
pulsestyle_onevent/_ondetect/showcancelled/noshowcancelled) are
validated against LRM 30.7.4.1/30.7.4.2’s declaration-order rule as
they are met, then applied to the PathEntrys whose outputs they name
once the module’s whole specify content has been walked
([discover_pulse_style], [apply_pulse_style_declarations]).
A TimingPath whose desugaring would need [EvalSession:: eval_constant] (a bit-select/part-select terminal whose index is
not already folded) is why this method takes eval, unlike
Self::seed_specparams — mirrors specify_eval:: eval_specparam_aware’s own reason for carrying one.