From 0036873c400ba3998fc2a6f73e03f45da36ae1b6 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 12 Nov 2025 03:36:40 -0800 Subject: [PATCH] WIP: add ExternModuleSimulatorState::read_past() -- test currently fails --- crates/fayalite/src/firrtl.rs | 1 + crates/fayalite/src/module.rs | 105 +++++-- .../src/module/transform/deduce_resets.rs | 1 + crates/fayalite/src/sim.rs | 260 +++++++++++++++-- crates/fayalite/src/sim/compiler.rs | 275 ++++++++++++++---- crates/fayalite/src/sim/value.rs | 38 +++ .../src/sim/value/sim_only_value_unsafe.rs | 18 +- crates/fayalite/tests/sim.rs | 115 ++++++++ .../fayalite/tests/sim/expected/array_rw.txt | 1 + .../expected/conditional_assignment_last.txt | 1 + .../tests/sim/expected/connect_const.txt | 1 + .../sim/expected/connect_const_reset.txt | 1 + .../tests/sim/expected/counter_async.txt | 35 +-- .../tests/sim/expected/counter_sync.txt | 17 +- .../tests/sim/expected/duplicate_names.txt | 1 + crates/fayalite/tests/sim/expected/enums.txt | 50 ++-- .../tests/sim/expected/extern_module.txt | 2 + .../tests/sim/expected/extern_module2.txt | 2 + .../tests/sim/expected/many_memories.txt | 1 + .../fayalite/tests/sim/expected/memories.txt | 1 + .../fayalite/tests/sim/expected/memories2.txt | 1 + .../fayalite/tests/sim/expected/memories3.txt | 1 + crates/fayalite/tests/sim/expected/mod1.txt | 1 + .../tests/sim/expected/phantom_const.txt | 1 + .../tests/sim/expected/ripple_counter.txt | 4 + .../tests/sim/expected/shift_register.txt | 17 +- .../tests/sim/expected/sim_fork_join.txt | 6 +- .../sim/expected/sim_fork_join_scope.txt | 6 +- .../tests/sim/expected/sim_only_connects.txt | 11 +- .../tests/sim/expected/sim_read_past.txt | 0 .../tests/sim/expected/sim_read_past.vcd | 0 .../expected/sim_resettable_counter_async.txt | 10 +- ...settable_counter_async_immediate_reset.txt | 10 +- .../expected/sim_resettable_counter_sync.txt | 8 +- ...esettable_counter_sync_immediate_reset.txt | 8 +- crates/fayalite/visit_types.json | 1 + 36 files changed, 840 insertions(+), 171 deletions(-) create mode 100644 crates/fayalite/tests/sim/expected/sim_read_past.txt create mode 100644 crates/fayalite/tests/sim/expected/sim_read_past.vcd diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index cca0d823..59fbec7f 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2326,6 +2326,7 @@ impl<'a> Exporter<'a> { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, + clocks_for_past: _, simulation: _, }) => { let verilog_name = Ident(verilog_name); diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 6527043c..5ffeaae2 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -41,7 +41,6 @@ use std::{ marker::PhantomData, mem, num::NonZeroU64, - ops::Deref, rc::Rc, sync::atomic::AtomicU64, }; @@ -67,6 +66,8 @@ pub trait ModuleBuildingStatus: type ModuleBody: fmt::Debug; type StmtAnnotations: 'static + Send + Sync + Copy + Eq + Hash + fmt::Debug; type ModuleIOAnnotations; + type ExternModuleParameters: fmt::Debug; + type ExternModuleClocksForPast: fmt::Debug; } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] @@ -79,6 +80,8 @@ impl ModuleBuildingStatus for ModuleBuilt { type ModuleBody = Block; type StmtAnnotations = Interned<[TargetedAnnotation]>; type ModuleIOAnnotations = Interned<[TargetedAnnotation]>; + type ExternModuleParameters = Interned<[ExternModuleParameter]>; + type ExternModuleClocksForPast = Interned<[Target]>; } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] @@ -91,6 +94,8 @@ impl ModuleBuildingStatus for ModuleBuilding { type ModuleBody = BuilderModuleBody; type StmtAnnotations = (); type ModuleIOAnnotations = Vec; + type ExternModuleParameters = Vec; + type ExternModuleClocksForPast = Vec; } #[derive(Debug)] @@ -1080,26 +1085,65 @@ impl From for ModuleBody { } } +#[track_caller] +fn validate_clock_for_past( + clock_for_past: Option, + module_io: &[AnnotatedModuleIO], +) -> Target { + if let Some(clock_for_past) = clock_for_past { + assert_eq!( + clock_for_past.canonical_ty(), + Clock.canonical(), + "clock_for_past: clock is not of type Clock", + ); + if clock_for_past + .base() + .module_io() + .is_some_and(|v| module_io.iter().any(|module_io| module_io.module_io == *v)) + { + let mut target = clock_for_past; + while let Target::Child(child) = target { + match *child.path_element() { + TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} + TargetPathElement::DynArrayElement(_) => { + panic!( + "clock_for_past: clock must be a static target (you can't use `Expr` array indexes):\n{clock_for_past:?}" + ); + } + } + target = *child.parent(); + } + return clock_for_past; + } + } + panic!("clock_for_past: clock must be some part of this module's I/O:\n{clock_for_past:?}"); +} + #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] -pub struct ExternModuleBody< - P: Deref = Interned<[ExternModuleParameter]>, -> { +pub struct ExternModuleBody { pub verilog_name: Interned, - pub parameters: P, + pub parameters: S::ExternModuleParameters, + /// [`Clock`]s that the [`Simulation`] will store the past values of all [`ModuleIO`] for. + /// + /// [`Simulation`]: crate::sim::Simulation + pub clocks_for_past: S::ExternModuleClocksForPast, pub simulation: Option, } -impl From>> for ExternModuleBody { - fn from(value: ExternModuleBody>) -> Self { +impl From> for ExternModuleBody { + fn from(value: ExternModuleBody) -> Self { let ExternModuleBody { verilog_name, parameters, + clocks_for_past, simulation, } = value; let parameters = Intern::intern_owned(parameters); + let clocks_for_past = Intern::intern_owned(clocks_for_past); Self { verilog_name, parameters, + clocks_for_past, simulation, } } @@ -1112,15 +1156,12 @@ impl From for ModuleBody { } #[derive(Debug)] -pub enum ModuleBody< - S: ModuleBuildingStatus = ModuleBuilt, - P: Deref = Interned<[ExternModuleParameter]>, -> { +pub enum ModuleBody { Normal(NormalModuleBody), - Extern(ExternModuleBody

), + Extern(ExternModuleBody), } -pub(crate) type ModuleBodyBuilding = ModuleBody>; +pub(crate) type ModuleBodyBuilding = ModuleBody; impl ModuleBodyBuilding { pub(crate) fn builder_normal_body_opt( @@ -1141,9 +1182,7 @@ impl ModuleBodyBuilding { } } #[track_caller] - pub(crate) fn builder_extern_body( - &mut self, - ) -> &mut ExternModuleBody> { + pub(crate) fn builder_extern_body(&mut self) -> &mut ExternModuleBody { if let Self::Extern(v) = self { v } else { @@ -1297,11 +1336,13 @@ impl fmt::Debug for DebugModuleBody { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, + clocks_for_past, simulation, }) => { debug_struct .field("verilog_name", verilog_name) .field("parameters", parameters) + .field("clocks_for_past", clocks_for_past) .field("simulation", simulation); } } @@ -1780,8 +1821,13 @@ impl AssertValidityState { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, + clocks_for_past, simulation: _, - }) => {} + }) => { + for clock_for_past in clocks_for_past { + validate_clock_for_past(Some(clock_for_past), &self.module.module_io); + } + } ModuleBody::Normal(NormalModuleBody { body }) => { let body = self.make_block_index(body); assert_eq!(body, 0); @@ -1811,9 +1857,17 @@ impl Module { match &mut body { ModuleBody::Normal(_) => {} ModuleBody::Extern(ExternModuleBody { + verilog_name: _, + parameters: _, + clocks_for_past, simulation: Some(simulation), - .. }) => { + let mut clocks_for_past_set = HashSet::default(); + *clocks_for_past = clocks_for_past + .iter() + .copied() + .filter(|clock_for_past| clocks_for_past_set.insert(*clock_for_past)) + .collect(); if module_io.iter().any(|io| { !simulation .sim_io_to_generator_map @@ -2186,6 +2240,7 @@ impl ModuleBuilder { ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody { verilog_name: name.0, parameters: vec![], + clocks_for_past: vec![], simulation: None, }), ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody { @@ -2308,6 +2363,20 @@ impl ModuleBuilder { value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()), }); } + /// registers a [`Clock`] so you can use it with the [`ExternModuleSimulationState::read_past()`] family of functions. + /// + /// [`ExternModuleSimulationState::read_past()`]: crate::sim::ExternModuleSimulationState::read_past() + #[track_caller] + pub fn register_clock_for_past(&self, clock_for_past: impl ToExpr) { + let clock_for_past = clock_for_past.to_expr().target().as_deref().copied(); + let mut impl_ = self.impl_.borrow_mut(); + let clock_for_past = validate_clock_for_past(clock_for_past, &impl_.io); + impl_ + .body + .builder_extern_body() + .clocks_for_past + .push(clock_for_past); + } #[track_caller] pub fn extern_module_simulation(&self, generator: G) { let mut impl_ = self.impl_.borrow_mut(); diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index e84d835e..bd4e939c 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -2073,6 +2073,7 @@ impl_run_pass_for_struct! { impl[] RunPass for ExternModuleBody { verilog_name: _, parameters: _, + clocks_for_past: _, simulation: _, } } diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 01233cb2..212d0d83 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -24,7 +24,7 @@ use crate::{ sim::{ compiler::{ Compiled, CompiledBundleField, CompiledExternModule, CompiledTypeLayoutBody, - CompiledValue, + CompiledValue, ExternModuleClockForPast, }, interpreter::{ BreakAction, BreakpointsSet, RunResult, SmallUInt, State, @@ -1040,6 +1040,12 @@ impl MaybeNeedsSettle { MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(f(v)), } } + fn into_inner(self) -> T { + match self { + MaybeNeedsSettle::NeedsSettle(v) => v, + MaybeNeedsSettle::NoSettleNeeded(v) => v, + } + } } // workaround implementing FnOnce not being stable @@ -1074,6 +1080,7 @@ struct SimulationModuleState { uninitialized_ios: HashMap>, io_targets: HashMap>, did_initial_settle: bool, + clocks_for_past: HashMap, SimulationExternModuleClockForPast>, } impl fmt::Debug for SimulationModuleState { @@ -1083,23 +1090,37 @@ impl fmt::Debug for SimulationModuleState { uninitialized_ios, io_targets, did_initial_settle, + clocks_for_past, } = self; f.debug_struct("SimulationModuleState") .field("base_targets", base_targets) .field("uninitialized_ios", &SortedSetDebug(uninitialized_ios)) .field("io_targets", &SortedSetDebug(io_targets)) .field("did_initial_settle", did_initial_settle) + .field("clocks_for_past", &SortedMapDebug(clocks_for_past)) .finish() } } impl SimulationModuleState { - fn new(base_targets: impl IntoIterator)>) -> Self { + fn new( + base_targets: impl IntoIterator)>, + clocks_for_past: &[ExternModuleClockForPast], + ) -> Self { let mut retval = Self { base_targets: Vec::new(), uninitialized_ios: HashMap::default(), io_targets: HashMap::default(), did_initial_settle: false, + clocks_for_past: clocks_for_past + .iter() + .map(|clock_for_past| { + ( + clock_for_past.clock_for_past, + SimulationExternModuleClockForPast::new(clock_for_past), + ) + }) + .collect(), }; for (base_target, value) in base_targets { retval.base_targets.push(base_target); @@ -1255,7 +1276,7 @@ impl SimulationModuleState { } } #[track_caller] - fn read_helper( + fn read_helper_current( &self, io: Expr, which_module: WhichModule, @@ -1300,6 +1321,33 @@ impl SimulationModuleState { } } #[track_caller] + fn read_helper( + &self, + io: Expr, + read_time: ReadTime, + which_module: WhichModule, + ) -> MaybeNeedsSettle> { + match read_time { + ReadTime::Current => self.read_helper_current(io, which_module), + ReadTime::Past { clock_for_past } => { + let current = self.read_helper_current(io, which_module); + let clock_for_past_value = self + .read_helper_current(Expr::canonical(clock_for_past), which_module) + .into_inner() + .map_ty(Clock::from_canonical); + let Some(clock_for_past) = self.clocks_for_past.get(&clock_for_past_value) else { + panic!( + "In order to use the `read_past()` family of functions,\n\ + you must call `m.register_clock_for_past(my_io.clk)`\n\ + in the module's body for every clock you use as the\n\ + second argument of the `read_past()` family." + ); + }; + current.map(|current| clock_for_past.current_to_past_map[¤t]) + } + } + } + #[track_caller] fn write_helper( &mut self, io: Expr, @@ -1331,6 +1379,65 @@ impl SimulationModuleState { } } +struct SimulationExternModuleClockForPast { + current_to_past_map: HashMap, CompiledValue>, +} + +impl fmt::Debug for SimulationExternModuleClockForPast { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + current_to_past_map, + } = self; + f.debug_struct("SimulationExternModuleClockForPast") + .field("current_to_past_map", &SortedMapDebug(current_to_past_map)) + .finish() + } +} + +impl SimulationExternModuleClockForPast { + fn new(clock_for_past: &ExternModuleClockForPast) -> Self { + let mut retval = Self { + current_to_past_map: HashMap::default(), + }; + for (current, past) in clock_for_past.current_to_past_map { + retval.add_current_to_past_mapping(current, past); + } + retval + } + fn add_current_to_past_mapping( + &mut self, + current: CompiledValue, + past: CompiledValue, + ) { + self.current_to_past_map.insert(current, past); + match current.layout.body { + CompiledTypeLayoutBody::Scalar | CompiledTypeLayoutBody::PhantomConst => {} + CompiledTypeLayoutBody::Array { .. } => { + let current = current.map_ty(Array::from_canonical); + let past = past.map_ty(Array::from_canonical); + for index in 0..current.layout.ty.len() { + self.add_current_to_past_mapping(current.element(index), past.element(index)); + } + } + CompiledTypeLayoutBody::Bundle { .. } => { + let current = current.map_ty(Bundle::from_canonical); + let past = past.map_ty(Bundle::from_canonical); + for BundleField { name, .. } in current.layout.ty.fields() { + self.add_current_to_past_mapping( + current.field_by_name(name), + past.field_by_name(name), + ); + } + } + } + } +} + +enum ReadTime { + Current, + Past { clock_for_past: Expr }, +} + struct SimulationExternModuleState { module_state: SimulationModuleState, sim: ExternModuleSimulation, @@ -1820,6 +1927,7 @@ impl SimulationImpl { &CompiledExternModule { module_io_targets, module_io, + clocks_for_past, simulation, }, )| { @@ -1829,6 +1937,7 @@ impl SimulationImpl { .iter() .copied() .zip(module_io.iter().copied()), + &clocks_for_past, ), sim: simulation, running_generator: None, @@ -1858,6 +1967,7 @@ impl SimulationImpl { value, ) }), + &[], ), extern_modules, trace_decls: compiled.base_module.trace_decls, @@ -2458,10 +2568,11 @@ impl SimulationImpl { fn read_bit( &mut self, io: Expr, + read_time: ReadTime, which_module: WhichModule, ) -> MaybeNeedsSettle { self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) + .read_helper(Expr::canonical(io), read_time, which_module) .map(|compiled_value| ReadBitFn { compiled_value }) .apply_no_settle(&mut self.state) } @@ -2485,10 +2596,11 @@ impl SimulationImpl { fn read_bool_or_int( &mut self, io: Expr, + read_time: ReadTime, which_module: WhichModule, ) -> MaybeNeedsSettle, I::Value> { self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) + .read_helper(Expr::canonical(io), read_time, which_module) .map(|compiled_value| ReadBoolOrIntFn { compiled_value, io }) .apply_no_settle(&mut self.state) } @@ -2569,17 +2681,18 @@ impl SimulationImpl { None => unreachable!(), } } - CompiledTypeLayoutBody::Array { element } => { + CompiledTypeLayoutBody::Array { elements_non_empty } => { let ty = ::from_canonical(compiled_value.layout.ty); let element_size = ty.element().size(); for element_index in 0..ty.len() { Self::read_write_sim_value_helper( state, CompiledValue { - layout: *element, - range: compiled_value - .range - .index_array(element.layout.len(), element_index), + layout: elements_non_empty[element_index], + range: compiled_value.range.index_array( + elements_non_empty[element_index].layout.len(), + element_index, + ), write: None, }, start_index + element_index * element_size, @@ -2725,12 +2838,15 @@ impl SimulationImpl { fn read( &mut self, io: Expr, + read_time: ReadTime, which_module: WhichModule, ) -> ( CompiledValue, MaybeNeedsSettle>, ) { - let compiled_value = self.get_module(which_module).read_helper(io, which_module); + let compiled_value = self + .get_module(which_module) + .read_helper(io, read_time, which_module); let value = compiled_value .map(|compiled_value| ReadFn { compiled_value, io }) .apply_no_settle(&mut self.state); @@ -2946,11 +3062,14 @@ impl fmt::Debug for SortedSetDebug<'_, T, V> { } } -struct SortedMapDebug<'a, K: 'static + Send + Sync, V>(&'a BTreeMap, V>); +struct SortedMapDebug<'a, T>(&'a T); -impl fmt::Debug for SortedMapDebug<'_, K, V> { +impl<'a, K: fmt::Debug + 'a, V: fmt::Debug + 'a, T> fmt::Debug for SortedMapDebug<'a, T> +where + &'a T: IntoIterator, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut entries = Vec::from_iter(self.0.iter().map(|(k, v)| { + let mut entries = Vec::from_iter(self.0.into_iter().map(|(k, v)| { if f.alternate() { (format!("{k:#?}"), format!("{v:#?}")) } else { @@ -3001,7 +3120,7 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read_bool_or_int(io, $which_module); + .read_bool_or_int(io, ReadTime::Current, $which_module); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? @@ -3032,7 +3151,7 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); + .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? @@ -3046,7 +3165,7 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); + .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? @@ -3060,7 +3179,7 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); + .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); $self.settle_if_needed(retval)$(.$await)? } #[track_caller] @@ -3075,7 +3194,7 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read(Expr::canonical(io), $which_module).1; + .read(Expr::canonical(io), ReadTime::Current, $which_module).1; SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) } $(#[$track_caller])? @@ -3211,7 +3330,10 @@ impl ExternModuleSimulationState { }; for io in iter { let io = Expr::canonical(io.to_expr()); - let (key, value) = self.sim_impl.borrow_mut().read(io, which_module); + let (key, value) = self + .sim_impl + .borrow_mut() + .read(io, ReadTime::Current, which_module); let value = self.settle_if_needed(value).await; let key = Rc::new(key); if sensitivity_set.compiled_values.insert(key.clone()) { @@ -3469,6 +3591,102 @@ impl ExternModuleSimulationState { .expect("filled by running all futures to completion"), } } + /// Reads the value of `io` from right before the last clock edge of `clock_for_past`. + /// + /// In order to use the `read_past()` family of functions, you must call [`m.register_clock_for_past(my_io.clk)`] + /// in the module's body for every clock you use as the second argument of the `read_past()` family. + /// + /// [`m.register_clock_for_past(my_io.clk)`]: crate::module::ModuleBuilder::register_clock_for_past + pub async fn read_past_bool_or_int( + &mut self, + io: Expr, + clock_for_past: Expr, + ) -> I::Value { + let retval = self.sim_impl.borrow_mut().read_bool_or_int( + io, + ReadTime::Past { clock_for_past }, + WhichModule::Extern { + module_index: self.module_index, + }, + ); + self.settle_if_needed(retval).await + } + /// Reads the value of `io` from right before the last clock edge of `clock_for_past`. + /// + /// In order to use the `read_past()` family of functions, you must call [`m.register_clock_for_past(my_io.clk)`] + /// in the module's body for every clock you use as the second argument of the `read_past()` family. + /// + /// [`m.register_clock_for_past(my_io.clk)`]: crate::module::ModuleBuilder::register_clock_for_past + pub async fn read_past_clock(&mut self, io: Expr, clock_for_past: Expr) -> bool { + let retval = self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Past { clock_for_past }, + WhichModule::Extern { + module_index: self.module_index, + }, + ); + self.settle_if_needed(retval).await + } + /// Reads the value of `io` from right before the last clock edge of `clock_for_past`. + /// + /// In order to use the `read_past()` family of functions, you must call [`m.register_clock_for_past(my_io.clk)`] + /// in the module's body for every clock you use as the second argument of the `read_past()` family. + /// + /// [`m.register_clock_for_past(my_io.clk)`]: crate::module::ModuleBuilder::register_clock_for_past + pub async fn read_past_bool(&mut self, io: Expr, clock_for_past: Expr) -> bool { + let retval = self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Past { clock_for_past }, + WhichModule::Extern { + module_index: self.module_index, + }, + ); + self.settle_if_needed(retval).await + } + /// Reads the value of `io` from right before the last clock edge of `clock_for_past`. + /// + /// In order to use the `read_past()` family of functions, you must call [`m.register_clock_for_past(my_io.clk)`] + /// in the module's body for every clock you use as the second argument of the `read_past()` family. + /// + /// [`m.register_clock_for_past(my_io.clk)`]: crate::module::ModuleBuilder::register_clock_for_past + pub async fn read_past_reset( + &mut self, + io: Expr, + clock_for_past: Expr, + ) -> bool { + let retval = self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Past { clock_for_past }, + WhichModule::Extern { + module_index: self.module_index, + }, + ); + self.settle_if_needed(retval).await + } + /// Reads the value of `io` from right before the last clock edge of `clock_for_past`. + /// + /// In order to use the `read_past()` family of functions, you must call [`m.register_clock_for_past(my_io.clk)`] + /// in the module's body for every clock you use as the second argument of the `read_past()` family. + /// + /// [`m.register_clock_for_past(my_io.clk)`]: crate::module::ModuleBuilder::register_clock_for_past + pub async fn read_past( + &mut self, + io: Expr, + clock_for_past: Expr, + ) -> SimValue { + let retval = self + .sim_impl + .borrow_mut() + .read( + Expr::canonical(io), + ReadTime::Past { clock_for_past }, + WhichModule::Extern { + module_index: self.module_index, + }, + ) + .1; + SimValue::from_canonical(self.settle_if_needed(retval).await) + } impl_simulation_methods!( async_await = (async, await), track_caller = (), @@ -3803,7 +4021,7 @@ impl fmt::Debug for ExternModuleSimulation { .field("generator", &self.generator) .field( "sim_io_to_generator_map", - &SortedMapDebug(&self.sim_io_to_generator_map), + &SortedMapDebug(&*self.sim_io_to_generator_map), ) .field("source_location", &self.source_location) .finish() diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index 98e5abfb..55919729 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -82,20 +82,73 @@ pub(crate) struct CompiledBundleField { pub(crate) ty: CompiledTypeLayout, } +impl CompiledBundleField { + fn with_prefixed_debug_names(self, prefix: &str) -> Self { + let Self { offset, ty } = self; + Self { + offset, + ty: ty.with_prefixed_debug_names(prefix), + } + } + fn with_anonymized_debug_info(self) -> Self { + let Self { offset, ty } = self; + Self { + offset, + ty: ty.with_anonymized_debug_info(), + } + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub(crate) enum CompiledTypeLayoutBody { Scalar, PhantomConst, Array { - /// debug names are ignored, use parent's layout instead - element: Interned>, + /// always has at least one element even for zero-sized arrays + elements_non_empty: Interned<[CompiledTypeLayout]>, }, Bundle { - /// debug names are ignored, use parent's layout instead fields: Interned<[CompiledBundleField]>, }, } +impl CompiledTypeLayoutBody { + fn with_prefixed_debug_names(self, prefix: &str) -> Self { + match self { + CompiledTypeLayoutBody::Scalar | CompiledTypeLayoutBody::PhantomConst => self, + CompiledTypeLayoutBody::Array { elements_non_empty } => CompiledTypeLayoutBody::Array { + elements_non_empty: elements_non_empty + .iter() + .map(|element| element.with_prefixed_debug_names(prefix)) + .collect(), + }, + CompiledTypeLayoutBody::Bundle { fields } => CompiledTypeLayoutBody::Bundle { + fields: fields + .iter() + .map(|field| field.with_prefixed_debug_names(prefix)) + .collect(), + }, + } + } + fn with_anonymized_debug_info(self) -> Self { + match self { + CompiledTypeLayoutBody::Scalar | CompiledTypeLayoutBody::PhantomConst => self, + CompiledTypeLayoutBody::Array { elements_non_empty } => CompiledTypeLayoutBody::Array { + elements_non_empty: elements_non_empty + .iter() + .map(|element| element.with_anonymized_debug_info()) + .collect(), + }, + CompiledTypeLayoutBody::Bundle { fields } => CompiledTypeLayoutBody::Bundle { + fields: fields + .iter() + .map(|field| field.with_anonymized_debug_info()) + .collect(), + }, + } + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub(crate) struct CompiledTypeLayout { pub(crate) ty: T, @@ -109,7 +162,7 @@ impl CompiledTypeLayout { Self { ty, layout: layout.with_prefixed_debug_names(prefix), - body, + body: body.with_prefixed_debug_names(prefix), } } fn with_anonymized_debug_info(self) -> Self { @@ -117,7 +170,7 @@ impl CompiledTypeLayout { Self { ty, layout: layout.with_anonymized_debug_info(), - body, + body: body.with_anonymized_debug_info(), } } fn get(ty: T) -> Self { @@ -152,18 +205,22 @@ impl CompiledTypeLayout { } CanonicalType::Array(array) => { let mut layout = TypeLayout::empty(); - let element = CompiledTypeLayout::get(array.element()).intern_sized(); + let element = CompiledTypeLayout::get(array.element()); + let mut elements_non_empty = vec![]; for index in 0..array.len() { - layout.allocate( - &element - .layout - .with_prefixed_debug_names(&format!("[{index}]")), - ); + let element = element.with_prefixed_debug_names(&format!("[{index}]")); + layout.allocate(&element.layout); + elements_non_empty.push(element); + } + if array.is_empty() { + elements_non_empty.push(element.with_prefixed_debug_names("[]")); } CompiledTypeLayout { ty: *input, layout: layout.into(), - body: CompiledTypeLayoutBody::Array { element }, + body: CompiledTypeLayoutBody::Array { + elements_non_empty: elements_non_empty.intern_deref(), + }, } } CanonicalType::PhantomConst(_) => CompiledTypeLayout { @@ -182,13 +239,9 @@ impl CompiledTypeLayout { flipped: _, ty, }| { - let ty = CompiledTypeLayout::get(*ty); - let offset = layout - .allocate( - &ty.layout - .with_prefixed_debug_names(&format!(".{name}")), - ) - .start(); + let ty = CompiledTypeLayout::get(*ty) + .with_prefixed_debug_names(&format!(".{name}")); + let offset = layout.allocate(&ty.layout).start(); CompiledBundleField { offset, ty } }, ) @@ -299,10 +352,13 @@ impl CompiledValue { impl CompiledValue { pub(crate) fn element(self, index: usize) -> CompiledValue { self.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { + let CompiledTypeLayoutBody::Array { elements_non_empty } = layout.body else { unreachable!(); }; - (*element, range.index_array(element.layout.len(), index)) + ( + elements_non_empty[index], + range.index_array(elements_non_empty[index].layout.len(), index), + ) }) } fn element_dyn( @@ -555,10 +611,11 @@ impl CompiledExpr { self, index_slot: StatePartIndex, ) -> CompiledExpr { - let CompiledTypeLayoutBody::Array { element } = self.static_part.layout.body else { + let CompiledTypeLayoutBody::Array { elements_non_empty } = self.static_part.layout.body + else { unreachable!(); }; - let stride = element.layout.len(); + let stride = elements_non_empty[0].layout.len(); let indexes = self.indexes.join(TypeArrayIndex::from_parts( index_slot, self.static_part.layout.ty.len(), @@ -566,10 +623,10 @@ impl CompiledExpr { )); CompiledExpr { static_part: self.static_part.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { + let CompiledTypeLayoutBody::Array { elements_non_empty } = layout.body else { unreachable!(); }; - (*element, range.index_array(stride, 0)) + (elements_non_empty[0], range.index_array(stride, 0)) }), indexes, } @@ -1548,6 +1605,13 @@ struct ClockTrigger { source_location: SourceLocation, } +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub(crate) struct ExternModuleClockForPast { + pub(crate) clock_for_past: CompiledValue, + pub(crate) current_to_past_map: + Interned<[(CompiledValue, CompiledValue)]>, +} + #[derive(Debug)] struct Register { value: CompiledValue, @@ -1635,6 +1699,7 @@ impl fmt::Debug for DebugOpaque { pub(crate) struct CompiledExternModule { pub(crate) module_io_targets: Interned<[Target]>, pub(crate) module_io: Interned<[CompiledValue]>, + pub(crate) clocks_for_past: Interned<[ExternModuleClockForPast]>, pub(crate) simulation: ExternModuleSimulation, } @@ -3915,18 +3980,15 @@ impl Compiler { self.enum_discriminants.insert(enum_value, retval); retval } - fn compile_stmt_reg( + fn compile_reg( &mut self, - stmt_reg: StmtReg, + clk: CompiledValue, + reset_and_init: Option<(Expr, CompiledValue)>, + source_location: SourceLocation, instantiated_module: InstantiatedModule, value: CompiledValue, ) { - let StmtReg { annotations, reg } = stmt_reg; - let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); - let clk = self - .compiled_expr_to_value(clk, reg.source_location()) - .map_ty(Clock::from_canonical); - let clk = self.compile_clock(clk, reg.source_location()); + let clk = self.compile_clock(clk, source_location); struct Dispatch; impl ResetTypeDispatch for Dispatch { type Input = (); @@ -3945,18 +4007,15 @@ impl Compiler { true } } - let reset = if let Some(init) = reg.init() { - let init = self.compile_expr(instantiated_module, init); - let init = self.compiled_expr_to_value(init, reg.source_location()); - let rst = - self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst)); - let rst = self.compiled_expr_to_value(rst, reg.source_location()); - let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location()); + let reset = if let Some((rst_expr, init)) = reset_and_init { + let rst = self.compile_expr(instantiated_module, Expr::canonical(rst_expr)); + let rst = self.compiled_expr_to_value(rst, source_location); + let rst = self.compiled_value_bool_dest_is_small(rst, source_location); let is_async = R::dispatch((), Dispatch); if is_async { - let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool)); + let cond = Expr::canonical(rst_expr.cast_to(Bool)); let cond = self.compile_expr(instantiated_module, cond); - let cond = self.compiled_expr_to_value(cond, reg.source_location()); + let cond = self.compiled_expr_to_value(cond, source_location); let cond = cond.map_ty(Bool::from_canonical); // write to the register's current value since asynchronous reset is combinational let lhs = CompiledValue { @@ -3968,12 +4027,12 @@ impl Compiler { self.compile_simple_connect( [Cond { body: CondBody::IfTrue { cond }, - source_location: reg.source_location(), + source_location: source_location, }] .intern_slice(), lhs, init, - reg.source_location(), + source_location, ); } Some(RegisterReset { @@ -3988,9 +4047,33 @@ impl Compiler { value, clk_triggered: clk.clk_triggered, reset, - source_location: reg.source_location(), + source_location, }); } + fn compile_stmt_reg( + &mut self, + stmt_reg: StmtReg, + instantiated_module: InstantiatedModule, + value: CompiledValue, + ) { + let StmtReg { annotations, reg } = stmt_reg; + let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); + let clk = self + .compiled_expr_to_value(clk, reg.source_location()) + .map_ty(Clock::from_canonical); + let reset_and_init = reg.init().map(|init| { + let init = self.compile_expr(instantiated_module, init); + let init = self.compiled_expr_to_value(init, reg.source_location()); + (reg.clock_domain().rst, init) + }); + self.compile_reg( + clk, + reset_and_init, + reg.source_location(), + instantiated_module, + value, + ); + } fn compile_declaration( &mut self, declaration: StmtDeclaration, @@ -4256,24 +4339,24 @@ impl Compiler { insns.push(end_label.into()); } } - CompiledTypeLayoutBody::Array { element } => { + CompiledTypeLayoutBody::Array { elements_non_empty } => { let CompiledTypeLayoutBody::Array { - element: mask_element, + elements_non_empty: mask_elements_non_empty, } = mask_layout.body else { unreachable!(); }; let ty = ::from_canonical(data_layout.ty); let element_bit_width = ty.element().bit_width(); - let element_size = element.layout.len(); - let mask_element_size = mask_element.layout.len(); + let element_size = elements_non_empty[0].layout.len(); + let mask_element_size = mask_elements_non_empty[0].layout.len(); for element_index in 0..ty.len() { self.compile_memory_port_rw_helper( memory, stride, start, - *element, - *mask_element, + elements_non_empty[element_index], + mask_elements_non_empty[element_index], read.as_mut().map( |MemoryPortReadInsns { addr, @@ -4880,6 +4963,88 @@ impl Compiler { } } } + fn compile_extern_module_clock_for_past( + &mut self, + instantiated_module: InstantiatedModule, + clock_for_past: Target, + ) -> ExternModuleClockForPast { + let clock_for_past = TargetInInstantiatedModule { + instantiated_module, + target: clock_for_past, + }; + let clock_for_past = self + .compile_value(clock_for_past) + .map_ty(Clock::from_canonical); + let clock_for_past_debug_name = match clock_for_past + .range + .len() + .as_single() + .expect("Clock is a single slot") + { + TypeLenSingle::BigSlot => { + self.insns + .state_layout + .ty + .big_slots + .debug_data(clock_for_past.range.start().big_slots) + .name + } + TypeLenSingle::SmallSlot => { + self.insns + .state_layout + .ty + .small_slots + .debug_data(clock_for_past.range.start().small_slots) + .name + } + TypeLenSingle::SimOnlySlot => { + unreachable!() + } + }; + let module_prefix = format!("{instantiated_module:?}."); + let trimmed_clock_for_past_debug_name = clock_for_past_debug_name + .strip_prefix(&module_prefix) + .unwrap_or(&clock_for_past_debug_name); + let current_to_past_map = instantiated_module + .leaf_module() + .module_io() + .iter() + .map( + |&AnnotatedModuleIO { + annotations: _, + module_io, + }| { + let target_base = TargetBase::from(module_io); + let current = self.compile_value(TargetInInstantiatedModule { + instantiated_module, + target: target_base.into(), + }); + let unprefixed_layout = CompiledTypeLayout::get(module_io.ty()); + let past_layout = unprefixed_layout.with_prefixed_debug_names(&format!( + "{module_prefix}{:?}$past({trimmed_clock_for_past_debug_name})", + target_base.target_name(), + )); + let past = CompiledValue { + range: self.insns.allocate_variable(&past_layout.layout), + layout: past_layout, + write: Some((current.layout, current.range)), + }; + self.compile_reg::( + clock_for_past, + None, + module_io.source_location(), + instantiated_module, + past, + ); + (current, past) + }, + ) + .collect(); + ExternModuleClockForPast { + clock_for_past, + current_to_past_map, + } + } fn compile_module(&mut self, module: Interned) -> &CompiledModule { let mut trace_decls = Vec::new(); let module_io = module @@ -4908,6 +5073,7 @@ impl Compiler { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, + clocks_for_past, simulation, }) => { let Some(simulation) = simulation else { @@ -4924,9 +5090,16 @@ impl Compiler { Target::from(*simulation.sim_io_to_generator_map[&v.module_io.intern()]) }) .collect(); + let clocks_for_past = clocks_for_past + .iter() + .map(|clock_for_past| { + self.compile_extern_module_clock_for_past(*module, *clock_for_past) + }) + .collect(); self.extern_modules.push(CompiledExternModule { module_io_targets, module_io, + clocks_for_past, simulation, }); } diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index 97174178..89eb4e60 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -394,6 +394,30 @@ impl SimValuePartialEq for Bool { } } +impl SimValuePartialEq for Clock { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + +impl SimValuePartialEq for Reset { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + +impl SimValuePartialEq for SyncReset { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + +impl SimValuePartialEq for AsyncReset { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + pub trait ToSimValue: ToSimValueWithType<::Type> { type Type: Type; @@ -1302,6 +1326,20 @@ impl ToSimValue for SimOnlyValue { } } +impl SimValuePartialEq for DynSimOnly { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + +impl, U: SimOnlyValueTrait> SimValuePartialEq> + for SimOnly +{ + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + ***this == ***other + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs index 98a199c8..3df80a8e 100644 --- a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs +++ b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs @@ -206,9 +206,25 @@ impl Default for SimOnly { } /// a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL -#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)] +#[derive(Clone, Eq, Hash, Default, Ord)] pub struct SimOnlyValue(Rc); +impl, U: SimOnlyValueTrait> PartialEq> + for SimOnlyValue +{ + fn eq(&self, other: &SimOnlyValue) -> bool { + >::eq(self, other) + } +} + +impl, U: SimOnlyValueTrait> PartialOrd> + for SimOnlyValue +{ + fn partial_cmp(&self, other: &SimOnlyValue) -> Option { + >::partial_cmp(self, other) + } +} + impl SimOnlyValue { pub fn with_dyn_ref R, R>(&self, f: F) -> R { // Safety: creating a copied `Rc` is safe as long as the copy isn't dropped and isn't changed diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 6d0380ba..f3ee262a 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -2375,3 +2375,118 @@ fn test_phantom_const() { panic!(); } } + +#[hdl_module(outline_generated, extern)] +pub fn sim_read_past() +where + ConstUsize: KnownSize, +{ + #[hdl] + let clocks: Array = m.input(); + #[hdl] + let outputs: Array, N> = m.output(); + #[hdl] + let past_clocks: Array = m.output(); + #[hdl] + let past_outputs: Array, N> = m.output(); + for clock in clocks { + m.register_clock_for_past(clock); + } + m.extern_module_simulation_fn( + (clocks, outputs, past_clocks, past_outputs), + |(clocks, outputs, past_clocks, past_outputs), mut sim| async move { + sim.write(outputs, [0u8; N]).await; + sim.write(past_clocks, [false; N]).await; + sim.write(past_outputs, [0u8; N]).await; + loop { + sim.fork_join_scope(|scope, _| async move { + for i in 0..N { + scope.spawn_detached( + move |_, mut sim: ExternModuleSimulationState| async move { + sim.wait_for_clock_edge(clocks[i]).await; + let v = sim + .read_bool_or_int(outputs[i]) + .await + .to_bigint() + .try_into() + .expect("known to be in range"); + sim.write(outputs[i], 1u8.wrapping_add(v)).await; + let v = sim.read_past(outputs, clocks[i]).await; + sim.write(past_outputs, v).await; + let v = sim.read_past(clocks, clocks[i]).await; + sim.write(past_clocks, v).await; + }, + ); + } + }) + .await; + } + }, + ); +} + +#[test] +fn test_sim_read_past() { + let _n = SourceLocation::normalize_files_for_tests(); + const N: usize = 3; + let mut sim = Simulation::new(sim_read_past::()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write(sim.io().clocks, [false; N]); + let mut clocks_triggered = [false; N]; + let mut expected = [0u8; N]; + for i0 in 0..N { + for i1 in 0..N { + for i2 in 0..N { + for i3 in 0..N { + let indexes = [i0, i1, i2, i3]; + for i in indexes { + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().clocks[i], true); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().clocks[i], false); + let mut past_clocks_expected = [false; N]; + past_clocks_expected[i] = true; + let past_expected = expected; + dbg!(past_expected); + if !clocks_triggered[i] { + expected[i] = expected[i].wrapping_add(1); + } + clocks_triggered[i] = true; + if clocks_triggered == [true; N] { + clocks_triggered = [false; N]; + } + let output = sim.read(sim.io().outputs); + assert_eq!(output, expected.to_sim_value(), "indexes={indexes:?} i={i}"); + let past_clocks = sim.read(sim.io().past_clocks); + assert_eq!( + past_clocks, + past_clocks_expected + .to_sim_value_with_type(Array::::default()), + "indexes={indexes:?} i={i}" + ); + let past_outputs = sim.read(sim.io().past_outputs); + dbg!(&past_outputs); + dbg!(&sim); + assert_eq!( + past_outputs, + past_expected.to_sim_value(), + "indexes={indexes:?} i={i}" + ); + } + } + } + } + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/sim_read_past.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/sim_read_past.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt index 2f25f359..27b040d2 100644 --- a/crates/fayalite/tests/sim/expected/array_rw.txt +++ b/crates/fayalite/tests/sim/expected/array_rw.txt @@ -826,6 +826,7 @@ Simulation { }.write_index, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt index 47997e5b..d4707926 100644 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt @@ -122,6 +122,7 @@ Simulation { }.i, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/connect_const.txt b/crates/fayalite/tests/sim/expected/connect_const.txt index ac6c052b..56ea4ad7 100644 --- a/crates/fayalite/tests/sim/expected/connect_const.txt +++ b/crates/fayalite/tests/sim/expected/connect_const.txt @@ -98,6 +98,7 @@ Simulation { }.o, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/connect_const_reset.txt b/crates/fayalite/tests/sim/expected/connect_const_reset.txt index 999f414c..a9c18783 100644 --- a/crates/fayalite/tests/sim/expected/connect_const_reset.txt +++ b/crates/fayalite/tests/sim/expected/connect_const_reset.txt @@ -141,6 +141,7 @@ Simulation { }.reset_out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/counter_async.txt b/crates/fayalite/tests/sim/expected/counter_async.txt index 7a43720e..86bde889 100644 --- a/crates/fayalite/tests/sim/expected/counter_async.txt +++ b/crates/fayalite/tests/sim/expected/counter_async.txt @@ -100,51 +100,51 @@ Simulation { dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: AsyncReset }, }, + 3: IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock }, + }, + 4: AndSmall { + dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, // at: module-XXXXXXXXXX.rs:1:1 - 3: Const { + 5: Const { dest: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, value: 0x3, }, // at: module-XXXXXXXXXX.rs:3:1 - 4: BranchIfZero { - target: 6, + 6: BranchIfZero { + target: 8, value: StatePartIndex(6), // (0x0) SlotDebugData { name: "", ty: Bool }, }, - 5: Copy { + 7: Copy { dest: StatePartIndex(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, src: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, }, // at: module-XXXXXXXXXX.rs:1:1 - 6: Add { + 8: Add { dest: StatePartIndex(8), // (0x4) SlotDebugData { name: "", ty: UInt<5> }, lhs: StatePartIndex(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, rhs: StatePartIndex(7), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, - 7: CastToUInt { + 9: CastToUInt { dest: StatePartIndex(9), // (0x4) SlotDebugData { name: "", ty: UInt<4> }, src: StatePartIndex(8), // (0x4) SlotDebugData { name: "", ty: UInt<5> }, dest_width: 4, }, // at: module-XXXXXXXXXX.rs:4:1 - 8: Copy { + 10: Copy { dest: StatePartIndex(4), // (0x4) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> }, src: StatePartIndex(9), // (0x4) SlotDebugData { name: "", ty: UInt<4> }, }, // at: module-XXXXXXXXXX.rs:6:1 - 9: Copy { + 11: Copy { dest: StatePartIndex(2), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count", ty: UInt<4> }, src: StatePartIndex(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, }, // at: module-XXXXXXXXXX.rs:3:1 - 10: IsNonZeroDestIsSmall { - dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock }, - }, - 11: AndSmall { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, 12: BranchIfSmallNonZero { target: 16, value: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, @@ -261,6 +261,7 @@ Simulation { }.count, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/counter_sync.txt b/crates/fayalite/tests/sim/expected/counter_sync.txt index b96ce5fd..0a7517e9 100644 --- a/crates/fayalite/tests/sim/expected/counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/counter_sync.txt @@ -112,21 +112,21 @@ Simulation { dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: SyncReset }, }, - // at: module-XXXXXXXXXX.rs:1:1 - 6: Const { - dest: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, - value: 0x3, - }, - // at: module-XXXXXXXXXX.rs:3:1 - 7: IsNonZeroDestIsSmall { + 6: IsNonZeroDestIsSmall { dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock }, }, - 8: AndSmall { + 7: AndSmall { dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, }, + // at: module-XXXXXXXXXX.rs:1:1 + 8: Const { + dest: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, + value: 0x3, + }, + // at: module-XXXXXXXXXX.rs:3:1 9: BranchIfSmallZero { target: 14, value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, @@ -242,6 +242,7 @@ Simulation { }.count, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt index e127210b..64bbbe63 100644 --- a/crates/fayalite/tests/sim/expected/duplicate_names.txt +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -102,6 +102,7 @@ Simulation { uninitialized_ios: {}, io_targets: {}, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt index eeef867d..a193e926 100644 --- a/crates/fayalite/tests/sim/expected/enums.txt +++ b/crates/fayalite/tests/sim/expected/enums.txt @@ -1003,65 +1003,64 @@ Simulation { dest: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.rst", ty: SyncReset }, }, + 97: IsNonZeroDestIsSmall { + dest: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.clk", ty: Clock }, + }, + 98: AndSmall { + dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, // at: module-XXXXXXXXXX.rs:1:1 - 97: Const { + 99: Const { dest: StatePartIndex(25), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, value: 0x0, }, - 98: Copy { + 100: Copy { dest: StatePartIndex(26), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, src: StatePartIndex(25), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, }, // at: module-XXXXXXXXXX.rs:12:1 - 99: BranchIfZero { - target: 107, + 101: BranchIfZero { + target: 109, value: StatePartIndex(2), // (0x1) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::en", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:13:1 - 100: BranchIfZero { - target: 102, + 102: BranchIfZero { + target: 104, value: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:14:1 - 101: Copy { + 103: Copy { dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, src: StatePartIndex(26), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, // at: module-XXXXXXXXXX.rs:13:1 - 102: BranchIfNonZero { - target: 107, + 104: BranchIfNonZero { + target: 109, value: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:15:1 - 103: BranchIfZero { - target: 105, + 105: BranchIfZero { + target: 107, value: StatePartIndex(48), // (0x0) SlotDebugData { name: "", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:16:1 - 104: Copy { + 106: Copy { dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, src: StatePartIndex(65), // (0xd) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, // at: module-XXXXXXXXXX.rs:15:1 - 105: BranchIfNonZero { - target: 107, + 107: BranchIfNonZero { + target: 109, value: StatePartIndex(48), // (0x0) SlotDebugData { name: "", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:17:1 - 106: Copy { + 108: Copy { dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, src: StatePartIndex(87), // (0x3e) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, - // at: module-XXXXXXXXXX.rs:11:1 - 107: IsNonZeroDestIsSmall { - dest: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.clk", ty: Clock }, - }, - 108: AndSmall { - dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, // at: module-XXXXXXXXXX.rs:10:1 109: Copy { dest: StatePartIndex(15), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b2_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, @@ -1454,6 +1453,7 @@ Simulation { }.which_out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt index 03349409..52f2b345 100644 --- a/crates/fayalite/tests/sim/expected/extern_module.txt +++ b/crates/fayalite/tests/sim/expected/extern_module.txt @@ -102,6 +102,7 @@ Simulation { }.o, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -136,6 +137,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { diff --git a/crates/fayalite/tests/sim/expected/extern_module2.txt b/crates/fayalite/tests/sim/expected/extern_module2.txt index 3d7cfaef..fa6e767e 100644 --- a/crates/fayalite/tests/sim/expected/extern_module2.txt +++ b/crates/fayalite/tests/sim/expected/extern_module2.txt @@ -121,6 +121,7 @@ Simulation { }.o, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -167,6 +168,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { diff --git a/crates/fayalite/tests/sim/expected/many_memories.txt b/crates/fayalite/tests/sim/expected/many_memories.txt index f311cf7e..c521d725 100644 --- a/crates/fayalite/tests/sim/expected/many_memories.txt +++ b/crates/fayalite/tests/sim/expected/many_memories.txt @@ -3834,6 +3834,7 @@ Simulation { }.w[7].mask, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/memories.txt b/crates/fayalite/tests/sim/expected/memories.txt index 03c5ee37..0358bb31 100644 --- a/crates/fayalite/tests/sim/expected/memories.txt +++ b/crates/fayalite/tests/sim/expected/memories.txt @@ -719,6 +719,7 @@ Simulation { }.w.mask.1, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/memories2.txt b/crates/fayalite/tests/sim/expected/memories2.txt index f1cb72b6..b4041ba1 100644 --- a/crates/fayalite/tests/sim/expected/memories2.txt +++ b/crates/fayalite/tests/sim/expected/memories2.txt @@ -677,6 +677,7 @@ Simulation { }.rw.wmode, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/memories3.txt b/crates/fayalite/tests/sim/expected/memories3.txt index 3166e17b..2213912c 100644 --- a/crates/fayalite/tests/sim/expected/memories3.txt +++ b/crates/fayalite/tests/sim/expected/memories3.txt @@ -1761,6 +1761,7 @@ Simulation { }.w.mask[7], }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/mod1.txt b/crates/fayalite/tests/sim/expected/mod1.txt index 355b6ee0..3f7a55e5 100644 --- a/crates/fayalite/tests/sim/expected/mod1.txt +++ b/crates/fayalite/tests/sim/expected/mod1.txt @@ -274,6 +274,7 @@ Simulation { }.o.o2, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/phantom_const.txt b/crates/fayalite/tests/sim/expected/phantom_const.txt index dbc8f129..8c2237dd 100644 --- a/crates/fayalite/tests/sim/expected/phantom_const.txt +++ b/crates/fayalite/tests/sim/expected/phantom_const.txt @@ -240,6 +240,7 @@ Simulation { }.out[1], }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt index 58189754..9e46be41 100644 --- a/crates/fayalite/tests/sim/expected/ripple_counter.txt +++ b/crates/fayalite/tests/sim/expected/ripple_counter.txt @@ -743,6 +743,7 @@ Simulation { }.o, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -777,6 +778,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -860,6 +862,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -943,6 +946,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { diff --git a/crates/fayalite/tests/sim/expected/shift_register.txt b/crates/fayalite/tests/sim/expected/shift_register.txt index 2ca06d2d..7dcf26c5 100644 --- a/crates/fayalite/tests/sim/expected/shift_register.txt +++ b/crates/fayalite/tests/sim/expected/shift_register.txt @@ -128,21 +128,21 @@ Simulation { dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", ty: SyncReset }, }, - // at: module-XXXXXXXXXX.rs:1:1 - 6: Const { - dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:5:1 - 7: IsNonZeroDestIsSmall { + 6: IsNonZeroDestIsSmall { dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", ty: Clock }, }, - 8: AndSmall { + 7: AndSmall { dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, }, + // at: module-XXXXXXXXXX.rs:1:1 + 8: Const { + dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "", ty: Bool }, + value: 0x0, + }, + // at: module-XXXXXXXXXX.rs:5:1 9: BranchIfSmallZero { target: 14, value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, @@ -337,6 +337,7 @@ Simulation { }.q, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [], trace_decls: TraceModule { diff --git a/crates/fayalite/tests/sim/expected/sim_fork_join.txt b/crates/fayalite/tests/sim/expected/sim_fork_join.txt index 4ad3e620..680fedb9 100644 --- a/crates/fayalite/tests/sim/expected/sim_fork_join.txt +++ b/crates/fayalite/tests/sim/expected/sim_fork_join.txt @@ -164,6 +164,7 @@ Simulation { }.outputs[2], }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -234,6 +235,7 @@ Simulation { }[2], }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -433,7 +435,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_fork_join: sim_fork_join).sim_fork_join::clocks[0]", ty: Clock, }, ], @@ -482,7 +484,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_fork_join: sim_fork_join).sim_fork_join::clocks[0]", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt b/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt index ba5577d4..40d16a90 100644 --- a/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt +++ b/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt @@ -164,6 +164,7 @@ Simulation { }.outputs[2], }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -234,6 +235,7 @@ Simulation { }[2], }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -433,7 +435,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_fork_join_scope: sim_fork_join_scope).sim_fork_join_scope::clocks[0]", ty: Clock, }, ], @@ -482,7 +484,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_fork_join_scope: sim_fork_join_scope).sim_fork_join_scope::clocks[0]", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_only_connects.txt b/crates/fayalite/tests/sim/expected/sim_only_connects.txt index 3c1605d1..15456d20 100644 --- a/crates/fayalite/tests/sim/expected/sim_only_connects.txt +++ b/crates/fayalite/tests/sim/expected/sim_only_connects.txt @@ -557,6 +557,7 @@ Simulation { }.out3, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -635,6 +636,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -794,6 +796,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -1559,7 +1562,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock, }, ], @@ -1609,7 +1612,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock, }, ], @@ -1658,7 +1661,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock, }, ], @@ -1707,7 +1710,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_read_past.txt b/crates/fayalite/tests/sim/expected/sim_read_past.txt new file mode 100644 index 00000000..e69de29b diff --git a/crates/fayalite/tests/sim/expected/sim_read_past.vcd b/crates/fayalite/tests/sim/expected/sim_read_past.vcd new file mode 100644 index 00000000..e69de29b diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt index 351f944c..7b11157c 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt @@ -121,6 +121,7 @@ Simulation { }.out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -187,6 +188,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -361,7 +363,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.rst", ty: AsyncReset, }, ], @@ -411,7 +413,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -460,7 +462,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.rst", ty: AsyncReset, }, ], @@ -509,7 +511,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt index abd7cf65..0ca767a7 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt @@ -121,6 +121,7 @@ Simulation { }.out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -187,6 +188,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -361,7 +363,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.rst", ty: AsyncReset, }, ], @@ -411,7 +413,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -460,7 +462,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.rst", ty: AsyncReset, }, ], @@ -509,7 +511,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt index 8ff0c2fd..4af2eb62 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt @@ -121,6 +121,7 @@ Simulation { }.out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -187,6 +188,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -361,7 +363,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -411,7 +413,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -460,7 +462,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt index e6819475..45f09d20 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt @@ -121,6 +121,7 @@ Simulation { }.out, }, did_initial_settle: true, + clocks_for_past: {}, }, extern_modules: [ SimulationExternModuleState { @@ -187,6 +188,7 @@ Simulation { }, }, did_initial_settle: true, + clocks_for_past: {}, }, sim: ExternModuleSimulation { generator: SimGeneratorFn { @@ -361,7 +363,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -411,7 +413,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], @@ -460,7 +462,7 @@ Simulation { len: 1, debug_data: [ SlotDebugData { - name: "", + name: "InstantiatedModule(sim_resettable_counter: sim_resettable_counter).sim_resettable_counter::cd.clk", ty: Clock, }, ], diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index 04227efe..a74cef91 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -162,6 +162,7 @@ "$kind": "Struct", "verilog_name": "Visible", "parameters": "Visible", + "clocks_for_past": "Visible", "simulation": "Visible" } },