From 450e1004b6eef6fcdce74a94e3bded3e0268610d Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 9 Mar 2025 23:14:14 -0700 Subject: [PATCH 01/10] fix using fayalite as a dependency --- crates/fayalite/src/phantom_const.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index 81f5d6f..b8f3f09 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -84,7 +84,7 @@ impl<'de> Deserialize<'de> for PhantomConstCanonicalValue { } pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug { - fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>; } @@ -94,7 +94,7 @@ where T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug, Interned: DeserializeOwned, { - fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { @@ -189,7 +189,8 @@ impl Memoize for PhantomConstCanonicalMemoize; fn inner(self, input: &Self::Input) -> Self::Output { - PhantomConstValue::deserialize(input.as_json_value()).expect("deserialization failed ") + PhantomConstValue::deserialize_value(input.as_json_value()) + .expect("deserialization failed ") } } From d453755bb2cd0b6f2340f3e49058d29a2ee279e8 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 10 Mar 2025 19:40:03 -0700 Subject: [PATCH 02/10] add ExprPartialEq/ExprPartialOrd impls for PhantomConst --- crates/fayalite/src/phantom_const.rs | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index b8f3f09..dd6cff6 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -4,6 +4,11 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ + expr::{ + ops::{ExprPartialEq, ExprPartialOrd}, + Expr, ToExpr, + }, + int::Bool, intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize}, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, @@ -272,3 +277,37 @@ where const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; } + +impl ExprPartialEq for PhantomConst { + fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + true.to_expr() + } + + fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + false.to_expr() + } +} + +impl ExprPartialOrd for PhantomConst { + fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + false.to_expr() + } + + fn cmp_le(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + true.to_expr() + } + + fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + false.to_expr() + } + + fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr { + assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + true.to_expr() + } +} From 920d8d875f80b970a996b4d45f06b145a07fba84 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 19 Mar 2025 17:10:51 -0700 Subject: [PATCH 03/10] add some missing #[track_caller] --- crates/fayalite/src/module.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 446746a..d26dc7b 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -2174,6 +2174,7 @@ impl ModuleBuilder { .builder_extern_body() .verilog_name = name.intern(); } + #[track_caller] pub fn parameter(&self, name: impl AsRef, value: ExternModuleParameterValue) { let name = name.as_ref(); self.impl_ @@ -2186,6 +2187,7 @@ impl ModuleBuilder { value, }); } + #[track_caller] pub fn parameter_int(&self, name: impl AsRef, value: impl Into) { let name = name.as_ref(); let value = value.into(); @@ -2199,6 +2201,7 @@ impl ModuleBuilder { value: ExternModuleParameterValue::Integer(value), }); } + #[track_caller] pub fn parameter_str(&self, name: impl AsRef, value: impl AsRef) { let name = name.as_ref(); let value = value.as_ref(); @@ -2212,6 +2215,7 @@ impl ModuleBuilder { value: ExternModuleParameterValue::String(value.intern()), }); } + #[track_caller] pub fn parameter_raw_verilog(&self, name: impl AsRef, raw_verilog: impl AsRef) { let name = name.as_ref(); let raw_verilog = raw_verilog.as_ref(); From d1bd176b288ab84e58e6f44bce432d13fa105452 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 19 Mar 2025 17:11:41 -0700 Subject: [PATCH 04/10] implement simulation of extern modules --- crates/fayalite/src/firrtl.rs | 1 + crates/fayalite/src/module.rs | 25 +- crates/fayalite/src/module/transform/visit.rs | 1 + crates/fayalite/src/sim.rs | 1453 ++++++++--- crates/fayalite/tests/sim.rs | 65 +- .../fayalite/tests/sim/expected/array_rw.txt | 1819 +++----------- .../expected/conditional_assignment_last.txt | 57 +- .../tests/sim/expected/connect_const.txt | 57 +- .../sim/expected/connect_const_reset.txt | 103 +- .../tests/sim/expected/counter_async.txt | 249 +- .../tests/sim/expected/counter_sync.txt | 249 +- .../tests/sim/expected/duplicate_names.txt | 12 +- crates/fayalite/tests/sim/expected/enums.txt | 497 +--- .../tests/sim/expected/extern_module.txt | 224 ++ .../tests/sim/expected/extern_module.vcd | 51 + .../fayalite/tests/sim/expected/memories.txt | 1436 ++--------- .../fayalite/tests/sim/expected/memories2.txt | 571 +---- .../fayalite/tests/sim/expected/memories3.txt | 2135 ++--------------- crates/fayalite/tests/sim/expected/mod1.txt | 349 +-- .../tests/sim/expected/shift_register.txt | 297 +-- crates/fayalite/visit_types.json | 9 +- 21 files changed, 2702 insertions(+), 6958 deletions(-) create mode 100644 crates/fayalite/tests/sim/expected/extern_module.txt create mode 100644 crates/fayalite/tests/sim/expected/extern_module.vcd diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index dd5fc2e..d082187 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2258,6 +2258,7 @@ impl<'a> Exporter<'a> { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, + simulation: _, }) => { let verilog_name = Ident(verilog_name); writeln!(body, "{indent}defname = {verilog_name}").unwrap(); diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index d26dc7b..87f86cc 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -21,6 +21,7 @@ use crate::{ memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, + sim::{ExternModuleSimGenerator, ExternModuleSimulation}, source_location::SourceLocation, ty::{CanonicalType, Type}, util::ScopedRef, @@ -1081,6 +1082,7 @@ pub struct ExternModuleBody< > { pub verilog_name: Interned, pub parameters: P, + pub simulation: Option>, } impl From>> for ExternModuleBody { @@ -1088,11 +1090,13 @@ impl From>> for ExternModuleBody { let ExternModuleBody { verilog_name, parameters, + simulation, } = value; let parameters = Intern::intern_owned(parameters); Self { verilog_name, parameters, + simulation, } } } @@ -1283,10 +1287,12 @@ impl fmt::Debug for DebugModuleBody { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, + simulation, }) => { debug_struct .field("verilog_name", verilog_name) - .field("parameters", parameters); + .field("parameters", parameters) + .field("simulation", simulation); } } debug_struct.finish_non_exhaustive() @@ -1761,7 +1767,12 @@ impl AssertValidityState { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, - }) => {} + simulation, + }) => { + if let Some(simulation) = simulation { + simulation.check_io_ty(self.module.io_ty); + } + } ModuleBody::Normal(NormalModuleBody { body }) => { let body = self.make_block_index(body); assert_eq!(body, 0); @@ -2108,6 +2119,7 @@ impl ModuleBuilder { ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody { verilog_name: name.0, parameters: vec![], + simulation: None, }), ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody { body: BuilderModuleBody { @@ -2229,6 +2241,15 @@ impl ModuleBuilder { value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()), }); } + #[track_caller] + pub fn extern_module_simulation(&self, generator: G) { + let mut impl_ = self.impl_.borrow_mut(); + let simulation = &mut impl_.body.builder_extern_body().simulation; + if simulation.is_some() { + panic!("already added an extern module simulation"); + } + *simulation = Some(ExternModuleSimulation::new(generator)); + } } #[track_caller] diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 662a578..526a62c 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -31,6 +31,7 @@ use crate::{ phantom_const::PhantomConst, reg::Reg, reset::{AsyncReset, Reset, ResetType, SyncReset}, + sim::ExternModuleSimulation, source_location::SourceLocation, ty::{CanonicalType, Type}, wire::Wire, diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 96f6dd9..a5d7d13 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -15,12 +15,15 @@ use crate::{ ExprEnum, Flow, ToLiteralBits, }, int::{BoolOrIntType, IntType, SIntValue, UIntValue}, - intern::{Intern, Interned, Memoize}, + intern::{ + Intern, Interned, InternedCompare, Memoize, PtrEqWithTypeId, SupportsPtrEqWithTypeId, + }, memory::PortKind, module::{ - transform::deduce_resets::deduce_resets, AnnotatedModuleIO, Block, Id, InstantiatedModule, - ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, - StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, + transform::deduce_resets::deduce_resets, AnnotatedModuleIO, Block, ExternModuleBody, Id, + InstantiatedModule, ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, + StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, + TargetInInstantiatedModule, }, prelude::*, reset::{ResetType, ResetTypeDispatch}, @@ -51,7 +54,19 @@ use petgraph::{ }, }; use std::{ - borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut, sync::Arc, + any::Any, + borrow::Cow, + cell::RefCell, + collections::BTreeSet, + fmt, + future::{Future, IntoFuture}, + marker::PhantomData, + mem, + ops::IndexMut, + pin::Pin, + rc::Rc, + sync::Arc, + task::Poll, }; mod interpreter; @@ -1617,12 +1632,21 @@ impl fmt::Debug for DebugOpaque { } } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +struct CompiledExternModule { + io_ty: Bundle, + module_io_targets: Interned<[Target]>, + module_io: Interned<[CompiledValue]>, + simulation: ExternModuleSimulation, +} + #[derive(Debug)] pub struct Compiler { insns: Insns, original_base_module: Interned>, base_module: Interned>, modules: HashMap, + extern_modules: Vec, compiled_values: HashMap>, compiled_exprs: HashMap, CompiledExpr>, compiled_exprs_to_values: HashMap, CompiledValue>, @@ -1651,6 +1675,7 @@ impl Compiler { original_base_module, base_module, modules: HashMap::new(), + extern_modules: Vec::new(), compiled_values: HashMap::new(), compiled_exprs: HashMap::new(), compiled_exprs_to_values: HashMap::new(), @@ -4676,8 +4701,28 @@ impl Compiler { ModuleBody::Normal(NormalModuleBody { body }) => { self.compile_block(module, body, Interned::default(), &mut trace_decls); } - ModuleBody::Extern(_extern_module_body) => { - todo!("simulating extern module: {:?}", module); + ModuleBody::Extern(ExternModuleBody { + verilog_name: _, + parameters: _, + simulation, + }) => { + let Some(simulation) = simulation else { + panic!( + "can't simulate extern module without extern_module_simulation: {}", + module.leaf_module().source_location() + ); + }; + self.extern_modules.push(CompiledExternModule { + io_ty: module.leaf_module().io_ty(), + module_io_targets: module + .leaf_module() + .module_io() + .iter() + .map(|v| Target::from(v.module_io)) + .collect(), + module_io, + simulation, + }); } } let hashbrown::hash_map::Entry::Vacant(entry) = self.modules.entry(*module) else { @@ -4958,6 +5003,7 @@ impl Compiler { Compiled { insns: Insns::from(self.insns).intern_sized(), base_module, + extern_modules: Intern::intern_owned(self.extern_modules), io: Instance::new_unchecked( ScopedNameId( NameId("".intern(), Id::new()), @@ -4990,6 +5036,7 @@ struct CompiledModule { pub struct Compiled { insns: Interned>, base_module: CompiledModule, + extern_modules: Interned<[CompiledExternModule]>, io: Instance, traces: SimTraces]>>, trace_memories: Interned<[(StatePartIndex, TraceMem)]>, @@ -5004,6 +5051,7 @@ impl Compiled { let Self { insns, base_module, + extern_modules, io, traces, trace_memories, @@ -5012,6 +5060,7 @@ impl Compiled { Compiled { insns, base_module, + extern_modules, io: Instance::from_canonical(io.canonical()), traces, trace_memories, @@ -5022,6 +5071,7 @@ impl Compiled { let Compiled { insns, base_module, + extern_modules, io, traces, trace_memories, @@ -5030,6 +5080,7 @@ impl Compiled { Self { insns, base_module, + extern_modules, io: Instance::from_canonical(io.canonical()), traces, trace_memories, @@ -6474,62 +6525,85 @@ macro_rules! impl_to_sim_value_for_int_value { impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); -struct SimulationImpl { - state: interpreter::State, - io: Expr, - uninitialized_inputs: HashMap>, - io_targets: HashMap>, - made_initial_step: bool, - needs_settle: bool, - trace_decls: TraceModule, - traces: SimTraces]>>, - trace_memories: HashMap, TraceMem>, - trace_writers: Vec>, - instant: SimInstant, - clocks_triggered: Interned<[StatePartIndex]>, - breakpoints: Option, +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +enum MaybeNeedsSettle { + NeedsSettle(S), + NoSettleNeeded(N), } -impl fmt::Debug for SimulationImpl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt(None, f) +impl MaybeNeedsSettle { + fn map(self, f: impl FnOnce(T) -> U) -> MaybeNeedsSettle { + match self { + MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(f(v)), + MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(f(v)), + } } } -impl SimulationImpl { - fn debug_fmt(&self, io: Option<&dyn fmt::Debug>, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// workaround implementing FnOnce not being stable +trait MaybeNeedsSettleFn { + type Output; + + fn call(self, arg: A) -> Self::Output; +} + +impl O, A, O> MaybeNeedsSettleFn for T { + type Output = O; + + fn call(self, arg: A) -> Self::Output { + self(arg) + } +} + +impl MaybeNeedsSettle { + fn apply_no_settle(self, arg: T) -> MaybeNeedsSettle + where + N: MaybeNeedsSettleFn, + { + match self { + MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(v), + MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(v.call(arg)), + } + } +} + +struct SimulationModuleState { + base_targets: Vec, + uninitialized_ios: HashMap>, + io_targets: HashMap>, + did_initial_settle: bool, +} + +impl fmt::Debug for SimulationModuleState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { - state, - io: self_io, - uninitialized_inputs, + base_targets, + uninitialized_ios, io_targets, - made_initial_step, - needs_settle, - trace_decls, - traces, - trace_memories, - trace_writers, - instant, - clocks_triggered, - breakpoints: _, + did_initial_settle, } = self; - f.debug_struct("Simulation") - .field("state", state) - .field("io", io.unwrap_or(self_io)) - .field( - "uninitialized_inputs", - &SortedSetDebug(uninitialized_inputs), - ) - .field("io_targets", &SortedMapDebug(io_targets)) - .field("made_initial_step", made_initial_step) - .field("needs_settle", needs_settle) - .field("trace_decls", trace_decls) - .field("traces", traces) - .field("trace_memories", trace_memories) - .field("trace_writers", trace_writers) - .field("instant", instant) - .field("clocks_triggered", clocks_triggered) - .finish_non_exhaustive() + 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) + .finish() + } +} + +impl SimulationModuleState { + fn new(base_targets: impl IntoIterator)>) -> Self { + let mut retval = Self { + base_targets: Vec::new(), + uninitialized_ios: HashMap::new(), + io_targets: HashMap::new(), + did_initial_settle: false, + }; + for (base_target, value) in base_targets { + retval.base_targets.push(base_target); + retval.parse_io(base_target, value); + } + retval } /// returns `true` if `target` or any sub-targets are uninitialized inputs fn parse_io(&mut self, target: Target, value: CompiledValue) -> bool { @@ -6538,7 +6612,7 @@ impl SimulationImpl { CompiledTypeLayoutBody::Scalar => match target.flow() { Flow::Source => false, Flow::Sink => { - self.uninitialized_inputs.insert(target, vec![]); + self.uninitialized_ios.insert(target, vec![]); true } Flow::Duplex => unreachable!(), @@ -6557,7 +6631,7 @@ impl SimulationImpl { if sub_targets.is_empty() { false } else { - self.uninitialized_inputs.insert(target, sub_targets); + self.uninitialized_ios.insert(target, sub_targets); true } } @@ -6575,20 +6649,406 @@ impl SimulationImpl { if sub_targets.is_empty() { false } else { - self.uninitialized_inputs.insert(target, sub_targets); + self.uninitialized_ios.insert(target, sub_targets); true } } } } + fn mark_target_as_initialized(&mut self, mut target: Target) { + fn remove_target_and_children( + uninitialized_ios: &mut HashMap>, + target: Target, + ) { + let Some(children) = uninitialized_ios.remove(&target) else { + return; + }; + for child in children { + remove_target_and_children(uninitialized_ios, child); + } + } + remove_target_and_children(&mut self.uninitialized_ios, target); + while let Some(target_child) = target.child() { + let parent = target_child.parent(); + for child in self + .uninitialized_ios + .get(&*parent) + .map(|v| &**v) + .unwrap_or(&[]) + { + if self.uninitialized_ios.contains_key(child) { + return; + } + } + target = *parent; + self.uninitialized_ios.remove(&target); + } + } + #[track_caller] + fn get_io( + &self, + mut target: Target, + which_module: WhichModule, + ) -> CompiledValue { + if let Some(&retval) = self.io_targets.get(&target) { + return retval; + } + loop { + target = match target { + Target::Base(_) => break, + Target::Child(child) => { + match *child.path_element() { + TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} + TargetPathElement::DynArrayElement(_) => panic!( + "simulator read/write expression must not have dynamic array indexes" + ), + } + *child.parent() + } + }; + } + match which_module { + WhichModule::Main => panic!( + "simulator read/write expression must be \ + an array element/field of `Simulation::io()`" + ), + WhichModule::Extern { .. } => panic!( + "simulator read/write expression must be \ + one of this module's inputs/outputs or an \ + array element/field of one of this module's inputs/outputs" + ), + } + } + #[track_caller] + fn read_helper( + &self, + io: Expr, + which_module: WhichModule, + ) -> MaybeNeedsSettle> { + let Some(target) = io.target() else { + match which_module { + WhichModule::Main => panic!( + "can't read from an expression that's not a field/element of `Simulation::io()`" + ), + WhichModule::Extern { .. } => panic!( + "can't read from an expression that's not based on one of this module's inputs/outputs" + ), + } + }; + let compiled_value = self.get_io(*target, which_module); + match target.flow() { + Flow::Source => { + if !self.uninitialized_ios.is_empty() { + match which_module { + WhichModule::Main => { + panic!("can't read from an output before initializing all inputs"); + } + WhichModule::Extern { .. } => { + panic!("can't read from an input before initializing all outputs"); + } + } + } + MaybeNeedsSettle::NeedsSettle(compiled_value) + } + Flow::Sink => { + if self.uninitialized_ios.contains_key(&*target) { + match which_module { + WhichModule::Main => panic!("can't read from an uninitialized input"), + WhichModule::Extern { .. } => { + panic!("can't read from an uninitialized output"); + } + } + } + MaybeNeedsSettle::NoSettleNeeded(compiled_value) + } + Flow::Duplex => unreachable!(), + } + } + #[track_caller] + fn write_helper( + &mut self, + io: Expr, + which_module: WhichModule, + ) -> CompiledValue { + let Some(target) = io.target() else { + match which_module { + WhichModule::Main => panic!( + "can't write to an expression that's not a field/element of `Simulation::io()`" + ), + WhichModule::Extern { .. } => panic!( + "can't write to an expression that's not based on one of this module's outputs" + ), + } + }; + let compiled_value = self.get_io(*target, which_module); + match target.flow() { + Flow::Source => match which_module { + WhichModule::Main => panic!("can't write to an output"), + WhichModule::Extern { .. } => panic!("can't write to an input"), + }, + Flow::Sink => {} + Flow::Duplex => unreachable!(), + } + if !self.did_initial_settle { + self.mark_target_as_initialized(*target); + } + compiled_value + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum WaitTarget { + /// Settle is less than Instant + Settle, + Instant(SimInstant), +} + +impl PartialOrd for WaitTarget { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for WaitTarget { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match (self, other) { + (WaitTarget::Settle, WaitTarget::Settle) => std::cmp::Ordering::Equal, + (WaitTarget::Settle, WaitTarget::Instant(_)) => std::cmp::Ordering::Less, + (WaitTarget::Instant(_), WaitTarget::Settle) => std::cmp::Ordering::Greater, + (WaitTarget::Instant(l), WaitTarget::Instant(r)) => l.cmp(r), + } + } +} + +struct SimulationExternModuleState { + module_state: SimulationModuleState, + io_ty: Bundle, + sim: ExternModuleSimulation, + running_generator: Option + 'static>>>, + wait_target: Option, +} + +impl fmt::Debug for SimulationExternModuleState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + module_state, + io_ty, + sim, + running_generator, + wait_target, + } = self; + f.debug_struct("SimulationExternModuleState") + .field("module_state", module_state) + .field("io_ty", io_ty) + .field("sim", sim) + .field( + "running_generator", + &running_generator.as_ref().map(|_| DebugAsDisplay("...")), + ) + .field("wait_target", wait_target) + .finish() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +enum WhichModule { + Main, + Extern { module_index: usize }, +} + +struct ReadBitFn { + compiled_value: CompiledValue, +} + +impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBitFn { + type Output = bool; + + fn call(self, state: &mut interpreter::State) -> Self::Output { + match self.compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { + state.small_slots[self.compiled_value.range.small_slots.start] != 0 + } + TypeLen::A_BIG_SLOT => !state.big_slots[self.compiled_value.range.big_slots.start] + .clone() + .is_zero(), + _ => unreachable!(), + } + } +} + +struct ReadBoolOrIntFn { + compiled_value: CompiledValue, + io: Expr, +} + +impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBoolOrIntFn { + type Output = I::Value; + + fn call(self, state: &mut interpreter::State) -> Self::Output { + let Self { compiled_value, io } = self; + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => Expr::ty(io) + .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), + TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( + state.big_slots[compiled_value.range.big_slots.start].clone(), + ), + _ => unreachable!(), + } + } +} + +struct ReadFn { + compiled_value: CompiledValue, + io: Expr, +} + +impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn { + type Output = SimValue; + + fn call(self, state: &mut interpreter::State) -> Self::Output { + let Self { compiled_value, io } = self; + let mut bits = BitVec::repeat(false, compiled_value.layout.ty.bit_width()); + SimulationImpl::read_write_sim_value_helper( + state, + compiled_value, + &mut bits, + |_signed, bits, value| ::copy_bits_from_bigint_wrapping(value, bits), + |_signed, bits, value| { + let bytes = value.to_le_bytes(); + let bitslice = BitSlice::::from_slice(&bytes); + bits.clone_from_bitslice(&bitslice[..bits.len()]); + }, + ); + SimValue { + ty: Expr::ty(io), + bits, + } + } +} + +struct GeneratorWaker; + +impl std::task::Wake for GeneratorWaker { + fn wake(self: Arc) { + panic!("can't await other kinds of futures in function passed to ExternalModuleSimulation"); + } +} + +#[derive(Default)] +struct ReadyToRunSet { + state_ready_to_run: bool, + extern_modules_ready_to_run: Vec, +} + +impl ReadyToRunSet { + fn clear(&mut self) { + let Self { + state_ready_to_run, + extern_modules_ready_to_run, + } = self; + *state_ready_to_run = false; + extern_modules_ready_to_run.clear(); + } +} + +struct SimulationImpl { + state: interpreter::State, + io: Expr, + main_module: SimulationModuleState, + extern_modules: Box<[SimulationExternModuleState]>, + state_ready_to_run: bool, + trace_decls: TraceModule, + traces: SimTraces]>>, + trace_memories: HashMap, TraceMem>, + trace_writers: Vec>, + instant: SimInstant, + clocks_triggered: Interned<[StatePartIndex]>, + breakpoints: Option, + generator_waker: std::task::Waker, +} + +impl fmt::Debug for SimulationImpl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug_fmt(None, f) + } +} + +impl SimulationImpl { + fn debug_fmt(&self, io: Option<&dyn fmt::Debug>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + state, + io: self_io, + main_module, + extern_modules, + state_ready_to_run, + trace_decls, + traces, + trace_memories, + trace_writers, + instant, + clocks_triggered, + breakpoints: _, + generator_waker: _, + } = self; + f.debug_struct("Simulation") + .field("state", state) + .field("io", io.unwrap_or(self_io)) + .field("main_module", main_module) + .field("extern_modules", extern_modules) + .field("state_ready_to_run", state_ready_to_run) + .field("trace_decls", trace_decls) + .field("traces", traces) + .field("trace_memories", trace_memories) + .field("trace_writers", trace_writers) + .field("instant", instant) + .field("clocks_triggered", clocks_triggered) + .finish_non_exhaustive() + } fn new(compiled: Compiled) -> Self { - let mut retval = Self { + let io_target = Target::from(compiled.io); + let extern_modules = Box::from_iter(compiled.extern_modules.iter().map( + |&CompiledExternModule { + io_ty, + module_io_targets, + module_io, + simulation, + }| { + SimulationExternModuleState { + module_state: SimulationModuleState::new( + module_io_targets + .iter() + .copied() + .zip(module_io.iter().copied()), + ), + io_ty, + sim: simulation, + running_generator: None, + wait_target: Some(WaitTarget::Settle), + } + }, + )); + Self { state: State::new(compiled.insns), io: compiled.io.to_expr(), - uninitialized_inputs: HashMap::new(), - io_targets: HashMap::new(), - made_initial_step: false, - needs_settle: true, + main_module: SimulationModuleState::new( + compiled + .io + .ty() + .fields() + .into_iter() + .zip(compiled.base_module.module_io) + .map(|(BundleField { name, .. }, value)| { + ( + io_target.join( + TargetPathElement::from(TargetPathBundleField { name }) + .intern_sized(), + ), + value, + ) + }), + ), + extern_modules, + state_ready_to_run: true, trace_decls: compiled.base_module.trace_decls, traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map( |&SimTrace { @@ -6606,22 +7066,8 @@ impl SimulationImpl { instant: SimInstant::START, clocks_triggered: compiled.clocks_triggered, breakpoints: None, - }; - let io_target = Target::from(compiled.io); - for (BundleField { name, .. }, value) in compiled - .io - .ty() - .fields() - .into_iter() - .zip(compiled.base_module.module_io) - { - retval.parse_io( - io_target - .join(TargetPathElement::from(TargetPathBundleField { name }).intern_sized()), - value, - ); + generator_waker: Arc::new(GeneratorWaker).into(), } - retval } fn write_traces( &mut self, @@ -6759,9 +7205,92 @@ impl SimulationImpl { } } #[track_caller] - fn advance_time(&mut self, duration: SimDuration) { - self.settle(); - self.instant += duration; + fn advance_time(this_ref: &Rc>, duration: SimDuration) { + let instant = this_ref.borrow().instant + duration; + Self::run_until(this_ref, WaitTarget::Instant(instant)); + } + #[must_use] + fn yield_advance_time_or_settle( + this: Rc>, + module_index: usize, + duration: Option, + ) -> impl Future + 'static { + struct MyGenerator { + sim: Rc>, + yielded_at_all: bool, + module_index: usize, + target: WaitTarget, + } + impl Future for MyGenerator { + type Output = (); + + fn poll( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll { + let this = &mut *self; + let yielded_at_all = mem::replace(&mut this.yielded_at_all, true); + let mut sim = this.sim.borrow_mut(); + let sim = &mut *sim; + assert!(cx.waker().will_wake(&sim.generator_waker), "can't use ExternModuleSimulationState's methods outside of ExternModuleSimulation"); + if let WaitTarget::Instant(target) = this.target { + if target < sim.instant { + this.target = WaitTarget::Settle; + } else if yielded_at_all && target == sim.instant { + this.target = WaitTarget::Settle; + } + } + if let WaitTarget::Settle = this.target { + if yielded_at_all { + return Poll::Ready(()); + } + } + let wait_target = sim.extern_modules[this.module_index] + .wait_target + .get_or_insert(this.target); + *wait_target = (*wait_target).min(this.target); + Poll::Pending + } + } + let target = duration.map_or(WaitTarget::Settle, |duration| { + WaitTarget::Instant(this.borrow().instant + duration) + }); + MyGenerator { + sim: this, + yielded_at_all: false, + module_index, + target, + } + } + /// returns the next `WaitTarget` and the set of things ready to run then. + fn get_ready_to_run_set(&self, ready_to_run_set: &mut ReadyToRunSet) -> Option { + ready_to_run_set.clear(); + let mut wait_target = None; + if self.state_ready_to_run { + ready_to_run_set.state_ready_to_run = true; + wait_target = Some(WaitTarget::Settle); + } + for (module_index, extern_module) in self.extern_modules.iter().enumerate() { + let Some(extern_module_wait_target) = extern_module.wait_target else { + continue; + }; + if let Some(wait_target) = &mut wait_target { + match extern_module_wait_target.cmp(wait_target) { + std::cmp::Ordering::Less => ready_to_run_set.clear(), + std::cmp::Ordering::Equal => {} + std::cmp::Ordering::Greater => continue, + } + } else { + wait_target = Some(extern_module_wait_target); + } + ready_to_run_set + .extern_modules_ready_to_run + .push(module_index); + } + wait_target + } + fn set_instant_no_sim(&mut self, instant: SimInstant) { + self.instant = instant; self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { match &mut trace_writer_state { TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(), @@ -6774,53 +7303,126 @@ impl SimulationImpl { }); } #[track_caller] - fn settle(&mut self) { + fn run_until(this_ref: &Rc>, run_target: WaitTarget) { + let mut this = this_ref.borrow_mut(); + let mut ready_to_run_set = ReadyToRunSet::default(); + let generator_waker = this.generator_waker.clone(); assert!( - self.uninitialized_inputs.is_empty(), + this.main_module.uninitialized_ios.is_empty(), "didn't initialize all inputs", ); - for _ in 0..100000 { - if !self.needs_settle { - return; - } - self.state.setup_call(0); - if self.breakpoints.is_some() { - loop { - match self - .state - .run(self.breakpoints.as_mut().expect("just checked")) - { - RunResult::Break(break_action) => { - println!( - "hit breakpoint at:\n{:?}", - self.state.debug_insn_at(self.state.pc), - ); - match break_action { - BreakAction::DumpStateAndContinue => { - println!("{self:#?}"); - } - BreakAction::Continue => {} - } - } - RunResult::Return(()) => break, - } + match run_target { + WaitTarget::Settle => {} + WaitTarget::Instant(run_target) => assert!(run_target >= this.instant), + } + let mut settle_cycle = 0; + let mut run_extern_modules = true; + loop { + assert!(settle_cycle < 100000, "settle(): took too many steps"); + settle_cycle += 1; + let next_wait_target = match this.get_ready_to_run_set(&mut ready_to_run_set) { + Some(next_wait_target) if next_wait_target <= run_target => next_wait_target, + _ => break, + }; + match next_wait_target { + WaitTarget::Settle => {} + WaitTarget::Instant(instant) => { + settle_cycle = 0; + this.set_instant_no_sim(instant); } - } else { - let RunResult::Return(()) = self.state.run(()); } - if self.made_initial_step { - self.read_traces::(); - } else { - self.read_traces::(); + if run_extern_modules { + for module_index in ready_to_run_set.extern_modules_ready_to_run.drain(..) { + let extern_module = &mut this.extern_modules[module_index]; + extern_module.wait_target = None; + let mut generator = if !extern_module.module_state.did_initial_settle { + let sim = extern_module.sim; + let io_ty = extern_module.io_ty; + drop(this); + Box::into_pin(sim.run(ExternModuleSimulationState { + sim_impl: this_ref.clone(), + module_index, + io_ty, + })) + } else if let Some(generator) = extern_module.running_generator.take() { + drop(this); + generator + } else { + continue; + }; + let generator = match generator + .as_mut() + .poll(&mut std::task::Context::from_waker(&generator_waker)) + { + Poll::Ready(()) => None, + Poll::Pending => Some(generator), + }; + this = this_ref.borrow_mut(); + this.extern_modules[module_index] + .module_state + .did_initial_settle = true; + if !this.extern_modules[module_index] + .module_state + .uninitialized_ios + .is_empty() + { + panic!( + "extern module didn't initialize all outputs before \ + waiting, settling, or reading any inputs: {}", + this.extern_modules[module_index].sim.source_location + ); + } + this.extern_modules[module_index].running_generator = generator; + } } - self.state.memory_write_log.sort_unstable(); - self.state.memory_write_log.dedup(); - self.made_initial_step = true; - self.needs_settle = self - .clocks_triggered - .iter() - .any(|i| self.state.small_slots[*i] != 0); - self.for_each_trace_writer_storing_error(|this, trace_writer_state| { + if ready_to_run_set.state_ready_to_run { + this.state_ready_to_run = false; + run_extern_modules = true; + this.state.setup_call(0); + if this.breakpoints.is_some() { + loop { + let this = &mut *this; + match this + .state + .run(this.breakpoints.as_mut().expect("just checked")) + { + RunResult::Break(break_action) => { + println!( + "hit breakpoint at:\n{:?}", + this.state.debug_insn_at(this.state.pc), + ); + match break_action { + BreakAction::DumpStateAndContinue => { + println!("{this:#?}"); + } + BreakAction::Continue => {} + } + } + RunResult::Return(()) => break, + } + } + } else { + let RunResult::Return(()) = this.state.run(()); + } + if this + .clocks_triggered + .iter() + .any(|i| this.state.small_slots[*i] != 0) + { + this.state_ready_to_run = true; + // wait for clocks to settle before running extern modules again + run_extern_modules = false; + } + } + if this.main_module.did_initial_settle { + this.read_traces::(); + } else { + this.read_traces::(); + } + this.state.memory_write_log.sort_unstable(); + this.state.memory_write_log.dedup(); + this.main_module.did_initial_settle = true; + this.for_each_trace_writer_storing_error(|this, trace_writer_state| { Ok(match trace_writer_state { TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( this.init_trace_writer(trace_writer_decls.write_decls( @@ -6838,114 +7440,48 @@ impl SimulationImpl { TraceWriterState::Errored(e) => TraceWriterState::Errored(e), }) }); - self.state.memory_write_log.clear(); + this.state.memory_write_log.clear(); } - panic!("settle(): took too many steps"); - } - #[track_caller] - fn get_io(&self, target: Target) -> CompiledValue { - if let Some(&retval) = self.io_targets.get(&target) { - return retval; - } - if Some(&target) == self.io.target().as_deref() - || Some(target.base()) != self.io.target().map(|v| v.base()) - { - panic!("simulator read/write expression must be an array element/field of `Simulation::io()`"); - }; - panic!("simulator read/write expression must not have dynamic array indexes"); - } - fn mark_target_as_initialized(&mut self, mut target: Target) { - fn remove_target_and_children( - uninitialized_inputs: &mut HashMap>, - target: Target, - ) { - let Some(children) = uninitialized_inputs.remove(&target) else { - return; - }; - for child in children { - remove_target_and_children(uninitialized_inputs, child); - } - } - remove_target_and_children(&mut self.uninitialized_inputs, target); - while let Some(target_child) = target.child() { - let parent = target_child.parent(); - for child in self - .uninitialized_inputs - .get(&*parent) - .map(|v| &**v) - .unwrap_or(&[]) - { - if self.uninitialized_inputs.contains_key(child) { - return; - } - } - target = *parent; - self.uninitialized_inputs.remove(&target); + match run_target { + WaitTarget::Settle => {} + WaitTarget::Instant(instant) => this.set_instant_no_sim(instant), } } #[track_caller] - fn read_helper(&mut self, io: Expr) -> CompiledValue { - let Some(target) = io.target() else { - panic!("can't read from expression that's not a field/element of `Simulation::io()`"); - }; - let compiled_value = self.get_io(*target); - if self.made_initial_step { - self.settle(); - } else { - match target.flow() { - Flow::Source => { - if !self.uninitialized_inputs.is_empty() { - panic!( - "can't read from an output before the simulation has made any steps" - ); - } - self.settle(); - } - Flow::Sink => { - if self.uninitialized_inputs.contains_key(&*target) { - panic!("can't read from an uninitialized input"); - } - } - Flow::Duplex => unreachable!(), - } - } - compiled_value + fn settle(this_ref: &Rc>) { + Self::run_until(this_ref, WaitTarget::Settle); } - #[track_caller] - fn write_helper(&mut self, io: Expr) -> CompiledValue { - let Some(target) = io.target() else { - panic!("can't write to an expression that's not a field/element of `Simulation::io()`"); - }; - let compiled_value = self.get_io(*target); - match target.flow() { - Flow::Source => { - panic!("can't write to an output"); - } - Flow::Sink => {} - Flow::Duplex => unreachable!(), + fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState { + match which_module { + WhichModule::Main => &self.main_module, + WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state, } - if !self.made_initial_step { - self.mark_target_as_initialized(*target); - } - self.needs_settle = true; - compiled_value } - #[track_caller] - fn read_bit(&mut self, io: Expr) -> bool { - let compiled_value = self.read_helper(Expr::canonical(io)); - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => { - self.state.small_slots[compiled_value.range.small_slots.start] != 0 + fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState { + match which_module { + WhichModule::Main => &mut self.main_module, + WhichModule::Extern { module_index } => { + &mut self.extern_modules[module_index].module_state } - TypeLen::A_BIG_SLOT => !self.state.big_slots[compiled_value.range.big_slots.start] - .clone() - .is_zero(), - _ => unreachable!(), } } #[track_caller] - fn write_bit(&mut self, io: Expr, value: bool) { - let compiled_value = self.write_helper(io); + fn read_bit( + &mut self, + io: Expr, + which_module: WhichModule, + ) -> MaybeNeedsSettle { + self.get_module(which_module) + .read_helper(Expr::canonical(io), which_module) + .map(|compiled_value| ReadBitFn { compiled_value }) + .apply_no_settle(&mut self.state) + } + #[track_caller] + fn write_bit(&mut self, io: Expr, value: bool, which_module: WhichModule) { + let compiled_value = self + .get_module_mut(which_module) + .write_helper(io, which_module); + self.state_ready_to_run = true; match compiled_value.range.len() { TypeLen::A_SMALL_SLOT => { self.state.small_slots[compiled_value.range.small_slots.start] = value as _; @@ -6957,21 +7493,27 @@ impl SimulationImpl { } } #[track_caller] - fn read_bool_or_int(&mut self, io: Expr) -> I::Value { - let compiled_value = self.read_helper(Expr::canonical(io)); - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => Expr::ty(io).value_from_int_wrapping( - self.state.small_slots[compiled_value.range.small_slots.start], - ), - TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( - self.state.big_slots[compiled_value.range.big_slots.start].clone(), - ), - _ => unreachable!(), - } + fn read_bool_or_int( + &mut self, + io: Expr, + which_module: WhichModule, + ) -> MaybeNeedsSettle, I::Value> { + self.get_module(which_module) + .read_helper(Expr::canonical(io), which_module) + .map(|compiled_value| ReadBoolOrIntFn { compiled_value, io }) + .apply_no_settle(&mut self.state) } #[track_caller] - fn write_bool_or_int(&mut self, io: Expr, value: I::Value) { - let compiled_value = self.write_helper(Expr::canonical(io)); + fn write_bool_or_int( + &mut self, + io: Expr, + value: I::Value, + which_module: WhichModule, + ) { + let compiled_value = self + .get_module_mut(which_module) + .write_helper(Expr::canonical(io), which_module); + self.state_ready_to_run = true; let value: BigInt = value.into(); match compiled_value.range.len() { TypeLen::A_SMALL_SLOT => { @@ -6989,7 +7531,7 @@ impl SimulationImpl { } #[track_caller] fn read_write_sim_value_helper( - &mut self, + state: &mut interpreter::State, compiled_value: CompiledValue, bits: &mut BitSlice, read_write_big_scalar: impl Fn(bool, &mut BitSlice, &mut BigInt) + Copy, @@ -7014,12 +7556,12 @@ impl SimulationImpl { TypeLen::A_SMALL_SLOT => read_write_small_scalar( signed, bits, - &mut self.state.small_slots[compiled_value.range.small_slots.start], + &mut state.small_slots[compiled_value.range.small_slots.start], ), TypeLen::A_BIG_SLOT => read_write_big_scalar( signed, bits, - &mut self.state.big_slots[compiled_value.range.big_slots.start], + &mut state.big_slots[compiled_value.range.big_slots.start], ), _ => unreachable!(), } @@ -7028,7 +7570,8 @@ impl SimulationImpl { let ty = ::from_canonical(compiled_value.layout.ty); let element_bit_width = ty.element().bit_width(); for element_index in 0..ty.len() { - self.read_write_sim_value_helper( + Self::read_write_sim_value_helper( + state, CompiledValue { layout: *element, range: compiled_value @@ -7052,7 +7595,8 @@ impl SimulationImpl { }, ) in ty.fields().iter().zip(ty.field_offsets()).zip(fields) { - self.read_write_sim_value_helper( + Self::read_write_sim_value_helper( + state, CompiledValue { layout: field_layout, range: compiled_value.range.slice(TypeIndexRange::new( @@ -7070,29 +7614,30 @@ impl SimulationImpl { } } #[track_caller] - fn read(&mut self, io: Expr) -> SimValue { - let compiled_value = self.read_helper(io); - let mut bits = BitVec::repeat(false, compiled_value.layout.ty.bit_width()); - self.read_write_sim_value_helper( - compiled_value, - &mut bits, - |_signed, bits, value| ::copy_bits_from_bigint_wrapping(value, bits), - |_signed, bits, value| { - let bytes = value.to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - bits.clone_from_bitslice(&bitslice[..bits.len()]); - }, - ); - SimValue { - ty: Expr::ty(io), - bits, - } + fn read( + &mut self, + io: Expr, + which_module: WhichModule, + ) -> MaybeNeedsSettle> { + self.get_module(which_module) + .read_helper(io, which_module) + .map(|compiled_value| ReadFn { compiled_value, io }) + .apply_no_settle(&mut self.state) } #[track_caller] - fn write(&mut self, io: Expr, value: SimValue) { - let compiled_value = self.write_helper(io); + fn write( + &mut self, + io: Expr, + value: SimValue, + which_module: WhichModule, + ) { + let compiled_value = self + .get_module_mut(which_module) + .write_helper(io, which_module); + self.state_ready_to_run = true; assert_eq!(Expr::ty(io), value.ty()); - self.read_write_sim_value_helper( + Self::read_write_sim_value_helper( + &mut self.state, compiled_value, &mut value.into_bits(), |signed, bits, value| { @@ -7112,6 +7657,35 @@ impl SimulationImpl { }, ); } + #[track_caller] + fn settle_if_needed(this_ref: &Rc>, v: MaybeNeedsSettle) -> O + where + for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, + { + match v { + MaybeNeedsSettle::NeedsSettle(v) => { + Self::settle(this_ref); + v.call(&mut this_ref.borrow_mut().state) + } + MaybeNeedsSettle::NoSettleNeeded(v) => v, + } + } + async fn yield_settle_if_needed( + this_ref: &Rc>, + module_index: usize, + v: MaybeNeedsSettle, + ) -> O + where + for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, + { + match v { + MaybeNeedsSettle::NeedsSettle(v) => { + Self::yield_advance_time_or_settle(this_ref.clone(), module_index, None).await; + v.call(&mut this_ref.borrow_mut().state) + } + MaybeNeedsSettle::NoSettleNeeded(v) => v, + } + } fn close_all_trace_writers(&mut self) -> std::io::Result<()> { let trace_writers = mem::take(&mut self.trace_writers); let mut retval = Ok(()); @@ -7181,17 +7755,17 @@ impl SimulationImpl { self.trace_writers = trace_writers; retval } - fn close(mut self) -> std::io::Result<()> { - if self.made_initial_step { - self.settle(); + fn close(this: Rc>) -> std::io::Result<()> { + if this.borrow().main_module.did_initial_settle { + Self::settle(&this); } - self.close_all_trace_writers() + this.borrow_mut().close_all_trace_writers() } - fn flush_traces(&mut self) -> std::io::Result<()> { - if self.made_initial_step { - self.settle(); + fn flush_traces(this_ref: &Rc>) -> std::io::Result<()> { + if this_ref.borrow().main_module.did_initial_settle { + Self::settle(this_ref); } - self.for_each_trace_writer_getting_error( + this_ref.borrow_mut().for_each_trace_writer_getting_error( |this, trace_writer: TraceWriterState| match trace_writer { TraceWriterState::Decls(v) => { let mut v = v.write_decls( @@ -7225,7 +7799,7 @@ impl Drop for SimulationImpl { } pub struct Simulation { - sim_impl: SimulationImpl, + sim_impl: Rc>, io: Expr, } @@ -7272,24 +7846,117 @@ impl fmt::Debug for SortedMapDebug<'_, K, V> { impl fmt::Debug for Simulation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { sim_impl, io } = self; - sim_impl.debug_fmt(Some(io), f) + sim_impl.borrow().debug_fmt(Some(io), f) } } +macro_rules! impl_simulation_methods { + ( + async_await = ($($async:tt, $await:tt)?), + track_caller = ($(#[$track_caller:tt])?), + which_module = |$self:ident| $which_module:expr, + ) => { + $(#[$track_caller])? + pub $($async)? fn read_bool_or_int(&mut $self, io: Expr) -> I::Value { + let retval = $self + .sim_impl + .borrow_mut() + .read_bool_or_int(io, $which_module); + $self.settle_if_needed(retval)$(.$await)? + } + $(#[$track_caller])? + pub $($async)? fn write_bool_or_int( + &mut $self, + io: Expr, + value: impl ToExpr, + ) { + let value = value.to_expr(); + assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); + let value = value + .to_literal_bits() + .expect("the value that is being written to an input must be a literal"); + $self.sim_impl.borrow_mut().write_bool_or_int( + io, + I::bits_to_value(Cow::Borrowed(&value)), + $which_module, + ); + } + $(#[$track_caller])? + pub $($async)? fn write_clock(&mut $self, io: Expr, value: bool) { + $self.sim_impl + .borrow_mut() + .write_bit(Expr::canonical(io), value, $which_module); + } + $(#[$track_caller])? + pub $($async)? fn read_clock(&mut $self, io: Expr) -> bool { + let retval = $self + .sim_impl + .borrow_mut() + .read_bit(Expr::canonical(io), $which_module); + $self.settle_if_needed(retval)$(.$await)? + } + $(#[$track_caller])? + pub $($async)? fn write_bool(&mut $self, io: Expr, value: bool) { + $self.sim_impl + .borrow_mut() + .write_bit(Expr::canonical(io), value, $which_module); + } + $(#[$track_caller])? + pub $($async)? fn read_bool(&mut $self, io: Expr) -> bool { + let retval = $self + .sim_impl + .borrow_mut() + .read_bit(Expr::canonical(io), $which_module); + $self.settle_if_needed(retval)$(.$await)? + } + $(#[$track_caller])? + pub $($async)? fn write_reset(&mut $self, io: Expr, value: bool) { + $self.sim_impl + .borrow_mut() + .write_bit(Expr::canonical(io), value, $which_module); + } + $(#[$track_caller])? + pub $($async)? fn read_reset(&mut $self, io: Expr) -> bool { + let retval = $self + .sim_impl + .borrow_mut() + .read_bit(Expr::canonical(io), $which_module); + $self.settle_if_needed(retval)$(.$await)? + } + $(#[$track_caller])? + pub $($async)? fn read(&mut $self, io: Expr) -> SimValue { + let retval = $self + .sim_impl + .borrow_mut() + .read(Expr::canonical(io), $which_module); + SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) + } + $(#[$track_caller])? + pub $($async)? fn write>(&mut $self, io: Expr, value: V) { + $self.sim_impl.borrow_mut().write( + Expr::canonical(io), + value.into_sim_value(Expr::ty(io)).into_canonical(), + $which_module, + ); + } + }; +} + impl Simulation { pub fn new(module: Interned>) -> Self { Self::from_compiled(Compiled::new(module)) } pub fn add_trace_writer(&mut self, writer: W) { self.sim_impl + .borrow_mut() .trace_writers .push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer))); } pub fn flush_traces(&mut self) -> std::io::Result<()> { - self.sim_impl.flush_traces() + SimulationImpl::flush_traces(&self.sim_impl) } pub fn close(self) -> std::io::Result<()> { - self.sim_impl.close() + SimulationImpl::close(self.sim_impl) } pub fn canonical(self) -> Simulation { let Self { sim_impl, io } = self; @@ -7312,77 +7979,215 @@ impl Simulation { let sim_impl = SimulationImpl::new(compiled.canonical()); Self { io: Expr::from_bundle(sim_impl.io), - sim_impl, + sim_impl: Rc::new(RefCell::new(sim_impl)), } } #[track_caller] pub fn settle(&mut self) { - self.sim_impl.settle(); + SimulationImpl::settle(&self.sim_impl); } #[track_caller] pub fn advance_time(&mut self, duration: SimDuration) { - self.sim_impl.advance_time(duration); + SimulationImpl::advance_time(&self.sim_impl, duration); } #[track_caller] - pub fn read_bool_or_int(&mut self, io: Expr) -> I::Value { - self.sim_impl.read_bool_or_int(io) - } - #[track_caller] - pub fn write_bool_or_int( - &mut self, - io: Expr, - value: impl ToExpr, - ) { - let value = value.to_expr(); - assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); - let value = value - .to_literal_bits() - .expect("the value that is being written to an input must be a literal"); - self.sim_impl - .write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value))); - } - #[track_caller] - pub fn write_clock(&mut self, io: Expr, value: bool) { - self.sim_impl.write_bit(Expr::canonical(io), value); - } - #[track_caller] - pub fn read_clock(&mut self, io: Expr) -> bool { - self.sim_impl.read_bit(Expr::canonical(io)) - } - #[track_caller] - pub fn write_bool(&mut self, io: Expr, value: bool) { - self.sim_impl.write_bit(Expr::canonical(io), value); - } - #[track_caller] - pub fn read_bool(&mut self, io: Expr) -> bool { - self.sim_impl.read_bit(Expr::canonical(io)) - } - #[track_caller] - pub fn write_reset(&mut self, io: Expr, value: bool) { - self.sim_impl.write_bit(Expr::canonical(io), value); - } - #[track_caller] - pub fn read_reset(&mut self, io: Expr) -> bool { - self.sim_impl.read_bit(Expr::canonical(io)) - } - #[track_caller] - pub fn read(&mut self, io: Expr) -> SimValue { - SimValue::from_canonical(self.sim_impl.read(Expr::canonical(io))) - } - #[track_caller] - pub fn write>(&mut self, io: Expr, value: V) { - self.sim_impl.write( - Expr::canonical(io), - value.into_sim_value(Expr::ty(io)).into_canonical(), - ); + fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O + where + for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, + { + SimulationImpl::settle_if_needed(&self.sim_impl, v) } + impl_simulation_methods!( + async_await = (), + track_caller = (#[track_caller]), + which_module = |self| WhichModule::Main, + ); #[doc(hidden)] /// This is explicitly unstable and may be changed/removed at any time pub fn set_breakpoints_unstable(&mut self, pcs: HashSet, trace: bool) { - self.sim_impl.breakpoints = Some(BreakpointsSet { + self.sim_impl.borrow_mut().breakpoints = Some(BreakpointsSet { last_was_break: false, set: pcs, trace, }); } } + +pub struct ExternModuleSimulationState { + sim_impl: Rc>, + module_index: usize, + io_ty: T, +} + +impl fmt::Debug for ExternModuleSimulationState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + sim_impl: _, + module_index, + io_ty, + } = self; + f.debug_struct("ExternModuleSimulationState") + .field("sim_impl", &DebugAsDisplay("...")) + .field("module_index", module_index) + .field("io_ty", io_ty) + .finish() + } +} + +impl ExternModuleSimulationState { + pub fn canonical(self) -> ExternModuleSimulationState { + let Self { + sim_impl, + module_index, + io_ty, + } = self; + ExternModuleSimulationState { + sim_impl, + module_index, + io_ty: Bundle::from_canonical(io_ty.canonical()), + } + } + pub fn from_canonical(sim: ExternModuleSimulationState) -> Self { + let ExternModuleSimulationState { + sim_impl, + module_index, + io_ty, + } = sim; + Self { + sim_impl, + module_index, + io_ty: T::from_canonical(io_ty.canonical()), + } + } + pub async fn settle(&mut self) { + SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None) + .await + } + pub async fn advance_time(&mut self, duration: SimDuration) { + SimulationImpl::yield_advance_time_or_settle( + self.sim_impl.clone(), + self.module_index, + Some(duration), + ) + .await + } + async fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O + where + for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, + { + SimulationImpl::yield_settle_if_needed(&self.sim_impl, self.module_index, v).await + } + impl_simulation_methods!( + async_await = (async, await), + track_caller = (), + which_module = |self| WhichModule::Extern { module_index: self.module_index }, + ); +} + +pub trait ExternModuleSimGenerator: + Clone + Eq + std::hash::Hash + Any + Send + Sync + fmt::Debug +{ + type IOType: BundleType; + + fn run<'a>( + &'a self, + sim: ExternModuleSimulationState, + ) -> impl IntoFuture + 'a; +} + +trait DynExternModuleSimGenerator: Any + Send + Sync + SupportsPtrEqWithTypeId + fmt::Debug { + fn dyn_run<'a>( + &'a self, + sim: ExternModuleSimulationState, + ) -> Box + 'a>; + #[track_caller] + fn check_io_ty(&self, io_ty: Bundle); +} + +impl DynExternModuleSimGenerator for T { + fn dyn_run<'a>( + &'a self, + sim: ExternModuleSimulationState, + ) -> Box + 'a> { + Box::new( + self.run(ExternModuleSimulationState::from_canonical(sim)) + .into_future(), + ) + } + #[track_caller] + fn check_io_ty(&self, io_ty: Bundle) { + T::IOType::from_canonical(io_ty.canonical()); + } +} + +impl InternedCompare for dyn DynExternModuleSimGenerator { + type InternedCompareKey = PtrEqWithTypeId; + + fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { + this.get_ptr_eq_with_type_id() + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct ExternModuleSimulation { + generator: Interned, + source_location: SourceLocation, + _phantom: PhantomData, +} + +impl ExternModuleSimulation { + pub fn new_with_loc( + source_location: SourceLocation, + generator: G, + ) -> Self { + Self { + generator: Interned::cast_unchecked( + generator.intern(), + |v| -> &dyn DynExternModuleSimGenerator { v }, + ), + source_location, + _phantom: PhantomData, + } + } + #[track_caller] + pub fn new(generator: G) -> Self { + Self::new_with_loc(SourceLocation::caller(), generator) + } + pub fn canonical(self) -> ExternModuleSimulation { + let Self { + generator, + source_location, + _phantom: _, + } = self; + ExternModuleSimulation { + generator, + source_location, + _phantom: PhantomData, + } + } + pub fn from_canonical(v: ExternModuleSimulation) -> Self { + let ExternModuleSimulation { + generator, + source_location, + _phantom: _, + } = v; + Self { + generator, + source_location, + _phantom: PhantomData, + } + } +} + +impl ExternModuleSimulation { + fn run( + &self, + sim: ExternModuleSimulationState, + ) -> Box + 'static> { + Interned::into_inner(self.generator).dyn_run(sim) + } + #[track_caller] + pub fn check_io_ty(self, io_ty: Bundle) { + self.generator.check_io_ty(io_ty); + } +} diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 8c8a10f..0265a7a 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -5,11 +5,14 @@ use fayalite::{ int::UIntValue, prelude::*, reset::ResetType, - sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, + sim::{ + time::SimDuration, vcd::VcdWriterDecls, ExternModuleSimGenerator, + ExternModuleSimulationState, Simulation, ToSimValue, + }, ty::StaticType, util::RcWriter, }; -use std::num::NonZeroUsize; +use std::{future::IntoFuture, num::NonZeroUsize}; #[hdl_module(outline_generated)] pub fn connect_const() { @@ -1443,3 +1446,61 @@ fn test_conditional_assignment_last() { panic!(); } } + +#[hdl_module(outline_generated, extern)] +pub fn extern_module() { + #[hdl] + let i: Bool = m.input(); + #[hdl] + let o: Bool = m.output(); + #[derive(Clone, Eq, PartialEq, Hash, Debug)] + struct Sim { + i: Expr, + o: Expr, + } + impl ExternModuleSimGenerator for Sim { + type IOType = extern_module; + + fn run<'a>( + &'a self, + mut sim: ExternModuleSimulationState, + ) -> impl IntoFuture + 'a { + let Self { i, o } = *self; + async move { + sim.write(o, true).await; + sim.advance_time(SimDuration::from_nanos(500)).await; + let mut invert = false; + loop { + sim.advance_time(SimDuration::from_micros(1)).await; + let v = sim.read_bool(i).await; + sim.write(o, v ^ invert).await; + invert = !invert; + } + } + } + } + m.extern_module_simulation(Sim { i, o }); +} + +#[test] +fn test_extern_module() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(extern_module()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write(sim.io().i, false); + sim.advance_time(SimDuration::from_micros(10)); + sim.write(sim.io().i, true); + sim.advance_time(SimDuration::from_micros(10)); + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/extern_module.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/extern_module.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt index f016e72..34643f2 100644 --- a/crates/fayalite/tests/sim/expected/array_rw.txt +++ b/crates/fayalite/tests/sim/expected/array_rw.txt @@ -488,1501 +488,338 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in: CompiledValue { - layout: CompiledTypeLayout { - ty: Array, 16>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 16, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", - ty: UInt<8>, - }, - ], - .. - }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, + }.array_in, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 16 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[0]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[10]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 10, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[11]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 11, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[12]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 12, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[13]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 13, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[14]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 14, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[15]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 15, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[1]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[2]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[3]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[4]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[5]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[6]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 6, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[7]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 7, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[8]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 8, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[9]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 9, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out: CompiledValue { - layout: CompiledTypeLayout { - ty: Array, 16>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 16, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 16, len: 16 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[0]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 16, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[10]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 26, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[11]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 27, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[12]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 28, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[13]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 29, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[14]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 30, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[15]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 31, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[1]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 17, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[2]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 18, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[3]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 19, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[4]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 20, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[5]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 21, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[6]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 22, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[7]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 23, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[8]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 24, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[9]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 25, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_data: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 33, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_index: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 32, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_data: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 35, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 36, len: 1 }, - }, - write: None, - }, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_index: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 34, len: 1 }, - }, - write: None, + }.array_out, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_index, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_data, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_index, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_data, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_en, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[0], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[10], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[11], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[12], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[13], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[14], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[15], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[1], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[2], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[3], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[4], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[5], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[6], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[7], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[8], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[9], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[0], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[10], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[11], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[12], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[13], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[14], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[15], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[1], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[2], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[3], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[4], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[5], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[6], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[7], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[8], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[9], + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_data, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_index, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_data, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_en, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_index, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "array_rw", children: [ diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt index 186e5a5..c4242c4 100644 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt @@ -92,45 +92,30 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::conditional_assignment_last, - instantiated: Module { - name: conditional_assignment_last, - .. - }, - }.i: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", - ty: Bool, - }, - ], - .. - }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::conditional_assignment_last, + instantiated: Module { + name: conditional_assignment_last, + .. }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, + }.i, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::conditional_assignment_last, + instantiated: Module { + name: conditional_assignment_last, + .. + }, + }.i, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "conditional_assignment_last", children: [ diff --git a/crates/fayalite/tests/sim/expected/connect_const.txt b/crates/fayalite/tests/sim/expected/connect_const.txt index e44c50d..d357741 100644 --- a/crates/fayalite/tests/sim/expected/connect_const.txt +++ b/crates/fayalite/tests/sim/expected/connect_const.txt @@ -68,45 +68,30 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::connect_const, - instantiated: Module { - name: connect_const, - .. - }, - }.o: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(connect_const: connect_const).connect_const::o", - ty: UInt<8>, - }, - ], - .. - }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::connect_const, + instantiated: Module { + name: connect_const, + .. }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, + }.o, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::connect_const, + instantiated: Module { + name: connect_const, + .. + }, + }.o, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "connect_const", children: [ diff --git a/crates/fayalite/tests/sim/expected/connect_const_reset.txt b/crates/fayalite/tests/sim/expected/connect_const_reset.txt index d1ab998..b3eb3ea 100644 --- a/crates/fayalite/tests/sim/expected/connect_const_reset.txt +++ b/crates/fayalite/tests/sim/expected/connect_const_reset.txt @@ -97,79 +97,44 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. - }, - }.bit_out: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::bit_out", - ty: Bool, - }, - ], - .. - }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. - }, - }.reset_out: CompiledValue { - layout: CompiledTypeLayout { - ty: AsyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out", - ty: AsyncReset, - }, - ], - .. - }, + }.reset_out, + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, + }.bit_out, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. + }, + }.bit_out, + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. + }, + }.reset_out, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "connect_const_reset", children: [ diff --git a/crates/fayalite/tests/sim/expected/counter_async.txt b/crates/fayalite/tests/sim/expected/counter_async.txt index 2e005a0..558d943 100644 --- a/crates/fayalite/tests/sim/expected/counter_async.txt +++ b/crates/fayalite/tests/sim/expected/counter_async.txt @@ -203,213 +203,58 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: AsyncReset, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::cd.rst", - ty: AsyncReset, - }, - ], - .. - }, + }.cd, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: AsyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: AsyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], + }.count, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 2 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.rst: CompiledValue { - layout: CompiledTypeLayout { - ty: AsyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: AsyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.count: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::count", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, + }.cd, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "counter", children: [ diff --git a/crates/fayalite/tests/sim/expected/counter_sync.txt b/crates/fayalite/tests/sim/expected/counter_sync.txt index 78fc200..d31db25 100644 --- a/crates/fayalite/tests/sim/expected/counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/counter_sync.txt @@ -184,213 +184,58 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::cd.rst", - ty: SyncReset, - }, - ], - .. - }, + }.cd, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], + }.count, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 2 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.rst: CompiledValue { - layout: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.count: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(counter: counter).counter::count", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, + }.cd, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "counter", children: [ diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt index 8a59861..5c6c18a 100644 --- a/crates/fayalite/tests/sim/expected/duplicate_names.txt +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -88,10 +88,14 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: {}, - made_initial_step: true, - needs_settle: false, + main_module: SimulationModuleState { + base_targets: [], + uninitialized_ios: {}, + io_targets: {}, + did_initial_settle: true, + }, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "duplicate_names", children: [ diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt index ebfae3e..089ea31 100644 --- a/crates/fayalite/tests/sim/expected/enums.txt +++ b/crates/fayalite/tests/sim/expected/enums.txt @@ -1215,389 +1215,128 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.b_out: CompiledValue { - layout: CompiledTypeLayout { - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::b_out", - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), - }, - }, - ], - .. - }, + }.cd, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 7, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::cd.rst", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 2 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd.rst: CompiledValue { - layout: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_in: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::data_in", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_out: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::data_out", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 6, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::en", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_in: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::which_in", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, - }, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_out: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::which_out", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 1 }, - }, - write: None, + }.en, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_in, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_in, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_out, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_out, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.b_out, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.b_out, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd.clk, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd.rst, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_in, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_out, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.en, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_in, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_out, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "enums", children: [ diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt new file mode 100644 index 0000000..cb575a5 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/extern_module.txt @@ -0,0 +1,224 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(extern_module: extern_module).extern_module::i", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(extern_module: extern_module).extern_module::o", + ty: Bool, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Return, + ], + .. + }, + pc: 0, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [], + }, + big_slots: StatePart { + value: [ + 1, + 1, + ], + }, + }, + io: Instance { + name: ::extern_module, + instantiated: Module { + name: extern_module, + .. + }, + }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::extern_module, + instantiated: Module { + name: extern_module, + .. + }, + }.i, + Instance { + name: ::extern_module, + instantiated: Module { + name: extern_module, + .. + }, + }.o, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::extern_module, + instantiated: Module { + name: extern_module, + .. + }, + }.i, + Instance { + name: ::extern_module, + instantiated: Module { + name: extern_module, + .. + }, + }.o, + }, + did_initial_settle: true, + }, + extern_modules: [ + SimulationExternModuleState { + module_state: SimulationModuleState { + base_targets: [ + ModuleIO { + name: extern_module::i, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module::o, + is_input: false, + ty: Bool, + .. + }, + ], + uninitialized_ios: {}, + io_targets: { + ModuleIO { + name: extern_module::i, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module::o, + is_input: false, + ty: Bool, + .. + }, + }, + did_initial_settle: true, + }, + io_ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + i: Bool, + /* offset = 1 */ + o: Bool, + }, + sim: ExternModuleSimulation { + generator: Sim { + i: ModuleIO { + name: extern_module::i, + is_input: true, + ty: Bool, + .. + }, + o: ModuleIO { + name: extern_module::o, + is_input: false, + ty: Bool, + .. + }, + }, + source_location: SourceLocation( + module-XXXXXXXXXX.rs:4:1, + ), + _phantom: PhantomData, + }, + running_generator: Some( + ..., + ), + wait_target: Some( + Instant( + 20.500000000000 μs, + ), + ), + }, + ], + state_ready_to_run: false, + trace_decls: TraceModule { + name: "extern_module", + children: [ + TraceModuleIO { + name: "i", + child: TraceBool { + location: TraceScalarId(0), + name: "i", + flow: Source, + }, + ty: Bool, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceBool { + location: TraceScalarId(1), + name: "o", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigBool { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigBool { + index: StatePartIndex(1), + }, + state: 0x1, + last_state: 0x1, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 20 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module.vcd b/crates/fayalite/tests/sim/expected/extern_module.vcd new file mode 100644 index 0000000..e026a50 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/extern_module.vcd @@ -0,0 +1,51 @@ +$timescale 1 ps $end +$scope module extern_module $end +$var wire 1 ! i $end +$var wire 1 " o $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +1" +$end +#500000 +#1500000 +0" +#2500000 +1" +#3500000 +0" +#4500000 +1" +#5500000 +0" +#6500000 +1" +#7500000 +0" +#8500000 +1" +#9500000 +0" +#10000000 +1! +#10500000 +#11500000 +1" +#12500000 +0" +#13500000 +1" +#14500000 +0" +#15500000 +1" +#16500000 +0" +#17500000 +1" +#18500000 +0" +#19500000 +1" +#20000000 diff --git a/crates/fayalite/tests/sim/expected/memories.txt b/crates/fayalite/tests/sim/expected/memories.txt index afccd8a..cd778d4 100644 --- a/crates/fayalite/tests/sim/expected/memories.txt +++ b/crates/fayalite/tests/sim/expected/memories.txt @@ -570,1309 +570,149 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 5, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::r.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::r.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::r.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::r.data.0", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::r.data.1", - ty: SInt<8>, - }, - ], - .. - }, + }.r, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: UInt<8>, - }, - SlotDebugData { - name: ".1", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - }, - ], + }.w, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 5 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.addr: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: UInt<8>, - }, - SlotDebugData { - name: ".1", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 2 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data.0: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data.1: CompiledValue { - layout: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, - /* offset = 22 */ - mask: Bundle { - /* offset = 0 */ - 0: Bool, - /* offset = 1 */ - 1: Bool, - }, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 7, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.data.0", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.data.1", - ty: SInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.mask.0", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories: memories).memories::w.mask.1", - ty: Bool, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: UInt<8>, - }, - SlotDebugData { - name: ".1", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(5), - }, - ty: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: Bool, - /* offset = 1 */ - 1: Bool, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: Bool, - }, - SlotDebugData { - name: ".1", - ty: Bool, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 7 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.addr: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 7, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: UInt<8>, - /* offset = 8 */ - 1: SInt<8>, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: UInt<8>, - }, - SlotDebugData { - name: ".1", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 8, len: 2 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data.0: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 8, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data.1: CompiledValue { - layout: CompiledTypeLayout { - ty: SInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 9, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 6, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - 0: Bool, - /* offset = 1 */ - 1: Bool, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: ".0", - ty: Bool, - }, - SlotDebugData { - name: ".1", - ty: Bool, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 10, len: 2 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask.0: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 10, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask.1: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 11, len: 1 }, - }, - write: None, + }.r, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.addr, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.clk, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data.0, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data.1, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.en, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.addr, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.clk, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data.0, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data.1, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.en, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask.0, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask.1, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "memories", children: [ diff --git a/crates/fayalite/tests/sim/expected/memories2.txt b/crates/fayalite/tests/sim/expected/memories2.txt index 5d90815..2359749 100644 --- a/crates/fayalite/tests/sim/expected/memories2.txt +++ b/crates/fayalite/tests/sim/expected/memories2.txt @@ -598,514 +598,79 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - addr: UInt<3>, - /* offset = 3 */ - en: Bool, - /* offset = 4 */ - clk: Clock, - #[hdl(flip)] /* offset = 5 */ - rdata: UInt<2>, - /* offset = 7 */ - wmode: Bool, - /* offset = 8 */ - wdata: UInt<2>, - /* offset = 10 */ - wmask: Bool, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 7, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.addr", - ty: UInt<3>, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.rdata", - ty: UInt<2>, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.wmode", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.wdata", - ty: UInt<2>, - }, - SlotDebugData { - name: "InstantiatedModule(memories2: memories2).memories2::rw.wmask", - ty: Bool, - }, - ], - .. - }, + }.rw, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(4), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(5), - }, - ty: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(6), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], + }.rw, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 7 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.addr: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.rdata: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wdata: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wmask: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 6, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wmode: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - }, - write: None, + }.rw.addr, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.clk, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.en, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.rdata, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wdata, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wmask, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wmode, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "memories2", children: [ diff --git a/crates/fayalite/tests/sim/expected/memories3.txt b/crates/fayalite/tests/sim/expected/memories3.txt index 7860bc5..ad12aa4 100644 --- a/crates/fayalite/tests/sim/expected/memories3.txt +++ b/crates/fayalite/tests/sim/expected/memories3.txt @@ -1486,1882 +1486,275 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - addr: UInt<3>, - /* offset = 3 */ - en: Bool, - /* offset = 4 */ - clk: Clock, - #[hdl(flip)] /* offset = 5 */ - data: Array, 8>, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 11, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.addr", - ty: UInt<3>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::r.data[7]", - ty: UInt<8>, - }, - ], - .. - }, + }.r, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: Array, 8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[7]", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - }, - ], + }.w, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 11 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.addr: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data: CompiledValue { - layout: CompiledTypeLayout { - ty: Array, 8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[7]", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 8 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[0]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[1]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[2]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 5, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[3]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 6, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[4]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 7, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[5]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 8, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[6]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 9, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[7]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 10, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - addr: UInt<3>, - /* offset = 3 */ - en: Bool, - /* offset = 4 */ - clk: Clock, - /* offset = 5 */ - data: Array, 8>, - /* offset = 69 */ - mask: Array, - }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 19, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.addr", - ty: UInt<3>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.data[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[0]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[1]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[2]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[3]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[4]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[5]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[6]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(memories3: memories3).memories3::w.mask[7]", - ty: Bool, - }, - ], - .. - }, - }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: Array, 8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[7]", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(11), - }, - ty: CompiledTypeLayout { - ty: Array, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: Bool, - }, - SlotDebugData { - name: "[1]", - ty: Bool, - }, - SlotDebugData { - name: "[2]", - ty: Bool, - }, - SlotDebugData { - name: "[3]", - ty: Bool, - }, - SlotDebugData { - name: "[4]", - ty: Bool, - }, - SlotDebugData { - name: "[5]", - ty: Bool, - }, - SlotDebugData { - name: "[6]", - ty: Bool, - }, - SlotDebugData { - name: "[7]", - ty: Bool, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - }, - ], - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 11, len: 19 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.addr: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<3>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<3>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 11, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 13, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data: CompiledValue { - layout: CompiledTypeLayout { - ty: Array, 8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "[7]", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 14, len: 8 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[0]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 14, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[1]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 15, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[2]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 16, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[3]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 17, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[4]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 18, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[5]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 19, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[6]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 20, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[7]: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<8>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 21, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.en: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 12, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask: CompiledValue { - layout: CompiledTypeLayout { - ty: Array, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 8, - debug_data: [ - SlotDebugData { - name: "[0]", - ty: Bool, - }, - SlotDebugData { - name: "[1]", - ty: Bool, - }, - SlotDebugData { - name: "[2]", - ty: Bool, - }, - SlotDebugData { - name: "[3]", - ty: Bool, - }, - SlotDebugData { - name: "[4]", - ty: Bool, - }, - SlotDebugData { - name: "[5]", - ty: Bool, - }, - SlotDebugData { - name: "[6]", - ty: Bool, - }, - SlotDebugData { - name: "[7]", - ty: Bool, - }, - ], - .. - }, - }, - body: Array { - element: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 22, len: 8 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[0]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 22, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[1]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 23, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[2]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 24, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[3]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 25, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[4]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 26, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[5]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 27, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[6]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 28, len: 1 }, - }, - write: None, - }, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[7]: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 29, len: 1 }, - }, - write: None, + }.r, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.addr, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.clk, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[0], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[1], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[2], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[3], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[4], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[5], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[6], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[7], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.en, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.addr, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.clk, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[0], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[1], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[2], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[3], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[4], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[5], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[6], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[7], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.en, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[0], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[1], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[2], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[3], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[4], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[5], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[6], + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[7], }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "memories3", children: [ diff --git a/crates/fayalite/tests/sim/expected/mod1.txt b/crates/fayalite/tests/sim/expected/mod1.txt index 5c2b7eb..3656247 100644 --- a/crates/fayalite/tests/sim/expected/mod1.txt +++ b/crates/fayalite/tests/sim/expected/mod1.txt @@ -216,313 +216,58 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - i: UInt<4>, - /* offset = 4 */ - o: SInt<2>, - #[hdl(flip)] /* offset = 6 */ - i2: SInt<2>, - /* offset = 8 */ - o2: UInt<4>, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 4, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(mod1: mod1).mod1::o.i", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(mod1: mod1).mod1::o.o", - ty: SInt<2>, - }, - SlotDebugData { - name: "InstantiatedModule(mod1: mod1).mod1::o.i2", - ty: SInt<2>, - }, - SlotDebugData { - name: "InstantiatedModule(mod1: mod1).mod1::o.o2", - ty: UInt<4>, - }, - ], - .. - }, + }.o, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(2), - }, - ty: CompiledTypeLayout { - ty: SInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(3), - }, - ty: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], + }.o, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 4 }, - }, - write: None, - }, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.i: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.i2: CompiledValue { - layout: CompiledTypeLayout { - ty: SInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.o: CompiledValue { - layout: CompiledTypeLayout { - ty: SInt<2>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SInt<2>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.o2: CompiledValue { - layout: CompiledTypeLayout { - ty: UInt<4>, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<4>, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, + }.o.i, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.i2, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.o, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.o2, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "mod1", children: [ diff --git a/crates/fayalite/tests/sim/expected/shift_register.txt b/crates/fayalite/tests/sim/expected/shift_register.txt index 73f6263..901cf70 100644 --- a/crates/fayalite/tests/sim/expected/shift_register.txt +++ b/crates/fayalite/tests/sim/expected/shift_register.txt @@ -265,247 +265,72 @@ Simulation { .. }, }, - uninitialized_inputs: {}, - io_targets: { - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd: CompiledValue { - layout: CompiledTypeLayout { - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. }, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", - ty: SyncReset, - }, - ], - .. - }, + }.cd, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. }, - body: Bundle { - fields: [ - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(0), - }, - ty: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - CompiledBundleField { - offset: TypeIndex { - small_slots: StatePartIndex(0), - big_slots: StatePartIndex(1), - }, - ty: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - }, - ], + }.d, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. }, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 2 }, - }, - write: None, - }, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd.clk: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 0, len: 1 }, - }, - write: None, - }, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd.rst: CompiledValue { - layout: CompiledTypeLayout { - ty: SyncReset, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: SyncReset, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - }, - write: None, - }, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.d: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(shift_register: shift_register).shift_register::d", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 2, len: 1 }, - }, - write: None, - }, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.q: CompiledValue { - layout: CompiledTypeLayout { - ty: Bool, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(shift_register: shift_register).shift_register::q", - ty: Bool, - }, - ], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 3, len: 1 }, - }, - write: None, + }.q, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.clk, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.rst, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.d, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.q, }, + did_initial_settle: true, }, - made_initial_step: true, - needs_settle: false, + extern_modules: [], + state_ready_to_run: false, trace_decls: TraceModule { name: "shift_register", children: [ diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index b284372..451dc90 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -160,7 +160,8 @@ "data": { "$kind": "Struct", "verilog_name": "Visible", - "parameters": "Visible" + "parameters": "Visible", + "simulation": "Visible" } }, "ExternModuleParameter": { @@ -1269,6 +1270,12 @@ "$kind": "Opaque" }, "generics": "" + }, + "ExternModuleSimulation": { + "data": { + "$kind": "Opaque" + }, + "generics": "" } } } \ No newline at end of file From ab9ff4f2db235fb605d0ec9ea7568d78f54f2575 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 21 Mar 2025 17:08:29 -0700 Subject: [PATCH 05/10] simplify setting an extern module simulation --- crates/fayalite/src/module.rs | 22 ++- crates/fayalite/src/sim.rs | 170 +++++++----------- crates/fayalite/tests/sim.rs | 43 ++--- .../tests/sim/expected/extern_module.txt | 36 ++-- crates/fayalite/visit_types.json | 3 +- 5 files changed, 111 insertions(+), 163 deletions(-) diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 87f86cc..1fcb529 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -34,6 +34,7 @@ use std::{ collections::VecDeque, convert::Infallible, fmt, + future::IntoFuture, hash::{Hash, Hasher}, iter::FusedIterator, marker::PhantomData, @@ -1082,7 +1083,7 @@ pub struct ExternModuleBody< > { pub verilog_name: Interned, pub parameters: P, - pub simulation: Option>, + pub simulation: Option, } impl From>> for ExternModuleBody { @@ -1767,12 +1768,8 @@ impl AssertValidityState { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, - simulation, - }) => { - if let Some(simulation) = simulation { - simulation.check_io_ty(self.module.io_ty); - } - } + simulation: _, + }) => {} ModuleBody::Normal(NormalModuleBody { body }) => { let body = self.make_block_index(body); assert_eq!(body, 0); @@ -2250,6 +2247,17 @@ impl ModuleBuilder { } *simulation = Some(ExternModuleSimulation::new(generator)); } + #[track_caller] + pub fn extern_module_simulation_fn< + Args: fmt::Debug + Clone + Hash + Eq + Send + Sync + 'static, + Fut: IntoFuture + 'static, + >( + &self, + args: Args, + f: fn(Args, crate::sim::ExternModuleSimulationState) -> Fut, + ) { + self.extern_module_simulation(crate::sim::SimGeneratorFn { args, f }); + } } #[track_caller] diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index a5d7d13..b12e9a8 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -60,6 +60,7 @@ use std::{ collections::BTreeSet, fmt, future::{Future, IntoFuture}, + hash::Hash, marker::PhantomData, mem, ops::IndexMut, @@ -1634,10 +1635,9 @@ impl fmt::Debug for DebugOpaque { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] struct CompiledExternModule { - io_ty: Bundle, module_io_targets: Interned<[Target]>, module_io: Interned<[CompiledValue]>, - simulation: ExternModuleSimulation, + simulation: ExternModuleSimulation, } #[derive(Debug)] @@ -4713,7 +4713,6 @@ impl Compiler { ); }; self.extern_modules.push(CompiledExternModule { - io_ty: module.leaf_module().io_ty(), module_io_targets: module .leaf_module() .module_io() @@ -6822,8 +6821,7 @@ impl Ord for WaitTarget { struct SimulationExternModuleState { module_state: SimulationModuleState, - io_ty: Bundle, - sim: ExternModuleSimulation, + sim: ExternModuleSimulation, running_generator: Option + 'static>>>, wait_target: Option, } @@ -6832,14 +6830,12 @@ impl fmt::Debug for SimulationExternModuleState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { module_state, - io_ty, sim, running_generator, wait_target, } = self; f.debug_struct("SimulationExternModuleState") .field("module_state", module_state) - .field("io_ty", io_ty) .field("sim", sim) .field( "running_generator", @@ -7008,7 +7004,6 @@ impl SimulationImpl { let io_target = Target::from(compiled.io); let extern_modules = Box::from_iter(compiled.extern_modules.iter().map( |&CompiledExternModule { - io_ty, module_io_targets, module_io, simulation, @@ -7020,7 +7015,6 @@ impl SimulationImpl { .copied() .zip(module_io.iter().copied()), ), - io_ty, sim: simulation, running_generator: None, wait_target: Some(WaitTarget::Settle), @@ -7337,12 +7331,10 @@ impl SimulationImpl { extern_module.wait_target = None; let mut generator = if !extern_module.module_state.did_initial_settle { let sim = extern_module.sim; - let io_ty = extern_module.io_ty; drop(this); Box::into_pin(sim.run(ExternModuleSimulationState { sim_impl: this_ref.clone(), module_index, - io_ty, })) } else if let Some(generator) = extern_module.running_generator.take() { drop(this); @@ -8013,52 +8005,25 @@ impl Simulation { } } -pub struct ExternModuleSimulationState { +pub struct ExternModuleSimulationState { sim_impl: Rc>, module_index: usize, - io_ty: T, } -impl fmt::Debug for ExternModuleSimulationState { +impl fmt::Debug for ExternModuleSimulationState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { sim_impl: _, module_index, - io_ty, } = self; f.debug_struct("ExternModuleSimulationState") .field("sim_impl", &DebugAsDisplay("...")) .field("module_index", module_index) - .field("io_ty", io_ty) .finish() } } -impl ExternModuleSimulationState { - pub fn canonical(self) -> ExternModuleSimulationState { - let Self { - sim_impl, - module_index, - io_ty, - } = self; - ExternModuleSimulationState { - sim_impl, - module_index, - io_ty: Bundle::from_canonical(io_ty.canonical()), - } - } - pub fn from_canonical(sim: ExternModuleSimulationState) -> Self { - let ExternModuleSimulationState { - sim_impl, - module_index, - io_ty, - } = sim; - Self { - sim_impl, - module_index, - io_ty: T::from_canonical(io_ty.canonical()), - } - } +impl ExternModuleSimulationState { pub async fn settle(&mut self) { SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None) .await @@ -8084,39 +8049,74 @@ impl ExternModuleSimulationState { ); } -pub trait ExternModuleSimGenerator: - Clone + Eq + std::hash::Hash + Any + Send + Sync + fmt::Debug -{ - type IOType: BundleType; +pub trait ExternModuleSimGenerator: Clone + Eq + Hash + Any + Send + Sync + fmt::Debug { + fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a; +} - fn run<'a>( - &'a self, - sim: ExternModuleSimulationState, - ) -> impl IntoFuture + 'a; +pub struct SimGeneratorFn { + pub args: Args, + pub f: fn(Args, ExternModuleSimulationState) -> Fut, +} + +impl fmt::Debug for SimGeneratorFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { args, f: _ } = self; + f.debug_struct("SimGeneratorFn") + .field("args", args) + .field("f", &DebugAsDisplay("...")) + .finish() + } +} + +impl Hash for SimGeneratorFn { + fn hash(&self, state: &mut H) { + let Self { args, f } = self; + args.hash(state); + f.hash(state); + } +} + +impl Eq for SimGeneratorFn {} + +impl PartialEq for SimGeneratorFn { + fn eq(&self, other: &Self) -> bool { + let Self { args, f } = self; + *args == other.args && *f == other.f + } +} + +impl Clone for SimGeneratorFn { + fn clone(&self) -> Self { + Self { + args: self.args.clone(), + f: self.f, + } + } +} + +impl Copy for SimGeneratorFn {} + +impl< + T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static, + Fut: IntoFuture + 'static, + > ExternModuleSimGenerator for SimGeneratorFn +{ + fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a { + (self.f)(self.args.clone(), sim) + } } trait DynExternModuleSimGenerator: Any + Send + Sync + SupportsPtrEqWithTypeId + fmt::Debug { - fn dyn_run<'a>( - &'a self, - sim: ExternModuleSimulationState, - ) -> Box + 'a>; - #[track_caller] - fn check_io_ty(&self, io_ty: Bundle); + fn dyn_run<'a>(&'a self, sim: ExternModuleSimulationState) + -> Box + 'a>; } impl DynExternModuleSimGenerator for T { fn dyn_run<'a>( &'a self, - sim: ExternModuleSimulationState, + sim: ExternModuleSimulationState, ) -> Box + 'a> { - Box::new( - self.run(ExternModuleSimulationState::from_canonical(sim)) - .into_future(), - ) - } - #[track_caller] - fn check_io_ty(&self, io_ty: Bundle) { - T::IOType::from_canonical(io_ty.canonical()); + Box::new(self.run(sim).into_future()) } } @@ -8129,13 +8129,12 @@ impl InternedCompare for dyn DynExternModuleSimGenerator { } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct ExternModuleSimulation { +pub struct ExternModuleSimulation { generator: Interned, source_location: SourceLocation, - _phantom: PhantomData, } -impl ExternModuleSimulation { +impl ExternModuleSimulation { pub fn new_with_loc( source_location: SourceLocation, generator: G, @@ -8146,48 +8145,13 @@ impl ExternModuleSimulation { |v| -> &dyn DynExternModuleSimGenerator { v }, ), source_location, - _phantom: PhantomData, } } #[track_caller] pub fn new(generator: G) -> Self { Self::new_with_loc(SourceLocation::caller(), generator) } - pub fn canonical(self) -> ExternModuleSimulation { - let Self { - generator, - source_location, - _phantom: _, - } = self; - ExternModuleSimulation { - generator, - source_location, - _phantom: PhantomData, - } - } - pub fn from_canonical(v: ExternModuleSimulation) -> Self { - let ExternModuleSimulation { - generator, - source_location, - _phantom: _, - } = v; - Self { - generator, - source_location, - _phantom: PhantomData, - } - } -} - -impl ExternModuleSimulation { - fn run( - &self, - sim: ExternModuleSimulationState, - ) -> Box + 'static> { + fn run(&self, sim: ExternModuleSimulationState) -> Box + 'static> { Interned::into_inner(self.generator).dyn_run(sim) } - #[track_caller] - pub fn check_io_ty(self, io_ty: Bundle) { - self.generator.check_io_ty(io_ty); - } } diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 0265a7a..e516f22 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -5,14 +5,11 @@ use fayalite::{ int::UIntValue, prelude::*, reset::ResetType, - sim::{ - time::SimDuration, vcd::VcdWriterDecls, ExternModuleSimGenerator, - ExternModuleSimulationState, Simulation, ToSimValue, - }, + sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, ty::StaticType, util::RcWriter, }; -use std::{future::IntoFuture, num::NonZeroUsize}; +use std::num::NonZeroUsize; #[hdl_module(outline_generated)] pub fn connect_const() { @@ -1453,33 +1450,17 @@ pub fn extern_module() { let i: Bool = m.input(); #[hdl] let o: Bool = m.output(); - #[derive(Clone, Eq, PartialEq, Hash, Debug)] - struct Sim { - i: Expr, - o: Expr, - } - impl ExternModuleSimGenerator for Sim { - type IOType = extern_module; - - fn run<'a>( - &'a self, - mut sim: ExternModuleSimulationState, - ) -> impl IntoFuture + 'a { - let Self { i, o } = *self; - async move { - sim.write(o, true).await; - sim.advance_time(SimDuration::from_nanos(500)).await; - let mut invert = false; - loop { - sim.advance_time(SimDuration::from_micros(1)).await; - let v = sim.read_bool(i).await; - sim.write(o, v ^ invert).await; - invert = !invert; - } - } + m.extern_module_simulation_fn((i, o), |(i, o), mut sim| async move { + sim.write(o, true).await; + sim.advance_time(SimDuration::from_nanos(500)).await; + let mut invert = false; + loop { + sim.advance_time(SimDuration::from_micros(1)).await; + let v = sim.read_bool(i).await; + sim.write(o, v ^ invert).await; + invert = !invert; } - } - m.extern_module_simulation(Sim { i, o }); + }); } #[test] diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt index cb575a5..23af0b2 100644 --- a/crates/fayalite/tests/sim/expected/extern_module.txt +++ b/crates/fayalite/tests/sim/expected/extern_module.txt @@ -128,31 +128,27 @@ Simulation { }, did_initial_settle: true, }, - io_ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - i: Bool, - /* offset = 1 */ - o: Bool, - }, sim: ExternModuleSimulation { - generator: Sim { - i: ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }, - o: ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }, + generator: SimGeneratorFn { + args: ( + ModuleIO { + name: extern_module::i, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module::o, + is_input: false, + ty: Bool, + .. + }, + ), + f: ..., }, source_location: SourceLocation( module-XXXXXXXXXX.rs:4:1, ), - _phantom: PhantomData, }, running_generator: Some( ..., diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index 451dc90..ff2050a 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -1274,8 +1274,7 @@ "ExternModuleSimulation": { "data": { "$kind": "Opaque" - }, - "generics": "" + } } } } \ No newline at end of file From a115585d5a7c20742bfcdd64d09416bb7fdf3a54 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 25 Mar 2025 18:26:48 -0700 Subject: [PATCH 06/10] simulator: allow external module generators to wait for value changes and/or clock edges --- crates/fayalite/src/int.rs | 6 + crates/fayalite/src/sim.rs | 636 +++++++++++++----- crates/fayalite/tests/sim.rs | 47 ++ .../tests/sim/expected/extern_module.txt | 4 +- .../tests/sim/expected/extern_module2.txt | 308 +++++++++ .../tests/sim/expected/extern_module2.vcd | 150 +++++ 6 files changed, 969 insertions(+), 182 deletions(-) create mode 100644 crates/fayalite/tests/sim/expected/extern_module2.txt create mode 100644 crates/fayalite/tests/sim/expected/extern_module2.vcd diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index 5d10b29..236f240 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -621,6 +621,12 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { let bitslice = &BitSlice::::from_slice(&bytes)[..width]; bits.clone_from_bitslice(bitslice); } + fn bits_equal_bigint_wrapping(v: &BigInt, bits: &BitSlice) -> bool { + bits.iter() + .by_vals() + .enumerate() + .all(|(bit_index, bit): (usize, bool)| v.bit(bit_index as u64) == bit) + } fn bits_to_bigint(bits: &BitSlice) -> BigInt { let sign_byte = if Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false) { 0xFF diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index b12e9a8..275b106 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -5904,12 +5904,21 @@ impl SimTraceKind { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SimValue { ty: T, bits: BitVec, } +impl fmt::Debug for SimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SimValue") + .field("ty", &self.ty) + .field("bits", &BitSliceWriteWithBase(&self.bits)) + .finish() + } +} + impl SimValue { #[track_caller] fn to_expr_impl(ty: CanonicalType, bits: &BitSlice) -> Expr { @@ -6795,35 +6804,149 @@ impl SimulationModuleState { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum WaitTarget { - /// Settle is less than Instant +#[derive(Copy, Clone, Debug)] +enum WaitTarget { Settle, Instant(SimInstant), + Change { key: ChangeKey, value: ChangeValue }, } -impl PartialOrd for WaitTarget { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) +#[derive(Clone)] +struct EarliestWaitTargets { + settle: bool, + instant: Option, + changes: HashMap, SimValue>, +} + +impl fmt::Debug for EarliestWaitTargets { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() } } -impl Ord for WaitTarget { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - match (self, other) { - (WaitTarget::Settle, WaitTarget::Settle) => std::cmp::Ordering::Equal, - (WaitTarget::Settle, WaitTarget::Instant(_)) => std::cmp::Ordering::Less, - (WaitTarget::Instant(_), WaitTarget::Settle) => std::cmp::Ordering::Greater, - (WaitTarget::Instant(l), WaitTarget::Instant(r)) => l.cmp(r), +impl Default for EarliestWaitTargets { + fn default() -> Self { + Self { + settle: false, + instant: None, + changes: HashMap::new(), } } } +impl EarliestWaitTargets { + fn settle() -> Self { + Self { + settle: true, + instant: None, + changes: HashMap::new(), + } + } + fn instant(instant: SimInstant) -> Self { + Self { + settle: false, + instant: Some(instant), + changes: HashMap::new(), + } + } + fn len(&self) -> usize { + self.settle as usize + self.instant.is_some() as usize + self.changes.len() + } + fn is_empty(&self) -> bool { + self.len() == 0 + } + fn clear(&mut self) { + let Self { + settle, + instant, + changes, + } = self; + *settle = false; + *instant = None; + changes.clear(); + } + fn insert( + &mut self, + value: impl std::borrow::Borrow, ChangeValue>>, + ) where + ChangeValue: std::borrow::Borrow>, + { + let value = value.borrow(); + match value { + WaitTarget::Settle => self.settle = true, + WaitTarget::Instant(instant) => { + if self.instant.is_none_or(|v| v > *instant) { + self.instant = Some(*instant); + } + } + WaitTarget::Change { key, value } => { + self.changes + .entry(*key) + .or_insert_with(|| value.borrow().clone()); + } + } + } + fn convert_earlier_instants_to_settle(&mut self, instant: SimInstant) { + if self.instant.is_some_and(|v| v <= instant) { + self.settle = true; + self.instant = None; + } + } + fn iter<'a>( + &'a self, + ) -> impl Clone + + Iterator, &'a SimValue>> + + 'a { + self.settle + .then_some(WaitTarget::Settle) + .into_iter() + .chain(self.instant.map(|instant| WaitTarget::Instant(instant))) + .chain( + self.changes + .iter() + .map(|(&key, value)| WaitTarget::Change { key, value }), + ) + } +} + +impl>> + Extend, ChangeValue>> for EarliestWaitTargets +{ + fn extend, ChangeValue>>>( + &mut self, + iter: T, + ) { + iter.into_iter().for_each(|v| self.insert(v)) + } +} + +impl<'a, ChangeValue: std::borrow::Borrow>> + Extend<&'a WaitTarget, ChangeValue>> for EarliestWaitTargets +{ + fn extend, ChangeValue>>>( + &mut self, + iter: T, + ) { + iter.into_iter().for_each(|v| self.insert(v)) + } +} + +impl FromIterator for EarliestWaitTargets +where + Self: Extend, +{ + fn from_iter>(iter: T) -> Self { + let mut retval = Self::default(); + retval.extend(iter); + retval + } +} + struct SimulationExternModuleState { module_state: SimulationModuleState, sim: ExternModuleSimulation, running_generator: Option + 'static>>>, - wait_target: Option, + wait_targets: EarliestWaitTargets, } impl fmt::Debug for SimulationExternModuleState { @@ -6832,7 +6955,7 @@ impl fmt::Debug for SimulationExternModuleState { module_state, sim, running_generator, - wait_target, + wait_targets, } = self; f.debug_struct("SimulationExternModuleState") .field("module_state", module_state) @@ -6841,7 +6964,7 @@ impl fmt::Debug for SimulationExternModuleState { "running_generator", &running_generator.as_ref().map(|_| DebugAsDisplay("...")), ) - .field("wait_target", wait_target) + .field("wait_targets", wait_targets) .finish() } } @@ -6896,29 +7019,19 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo struct ReadFn { compiled_value: CompiledValue, io: Expr, + bits: BitVec, } impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn { type Output = SimValue; fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { compiled_value, io } = self; - let mut bits = BitVec::repeat(false, compiled_value.layout.ty.bit_width()); - SimulationImpl::read_write_sim_value_helper( - state, + let Self { compiled_value, - &mut bits, - |_signed, bits, value| ::copy_bits_from_bigint_wrapping(value, bits), - |_signed, bits, value| { - let bytes = value.to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - bits.clone_from_bitslice(&bitslice[..bits.len()]); - }, - ); - SimValue { - ty: Expr::ty(io), + io, bits, - } + } = self; + SimulationImpl::read_no_settle_helper(state, io, compiled_value, bits) } } @@ -7017,7 +7130,7 @@ impl SimulationImpl { ), sim: simulation, running_generator: None, - wait_target: Some(WaitTarget::Settle), + wait_targets: EarliestWaitTargets::settle(), } }, )); @@ -7200,22 +7313,23 @@ impl SimulationImpl { } #[track_caller] fn advance_time(this_ref: &Rc>, duration: SimDuration) { - let instant = this_ref.borrow().instant + duration; - Self::run_until(this_ref, WaitTarget::Instant(instant)); + let run_target = this_ref.borrow().instant + duration; + Self::run_until(this_ref, run_target); } + /// clears `targets` #[must_use] - fn yield_advance_time_or_settle( + fn yield_wait<'a>( this: Rc>, module_index: usize, - duration: Option, - ) -> impl Future + 'static { - struct MyGenerator { + targets: &'a mut EarliestWaitTargets, + ) -> impl Future + 'a { + struct MyGenerator<'a> { sim: Rc>, yielded_at_all: bool, module_index: usize, - target: WaitTarget, + targets: &'a mut EarliestWaitTargets, } - impl Future for MyGenerator { + impl Future for MyGenerator<'_> { type Output = (); fn poll( @@ -7223,65 +7337,92 @@ impl SimulationImpl { cx: &mut std::task::Context<'_>, ) -> Poll { let this = &mut *self; - let yielded_at_all = mem::replace(&mut this.yielded_at_all, true); let mut sim = this.sim.borrow_mut(); let sim = &mut *sim; assert!(cx.waker().will_wake(&sim.generator_waker), "can't use ExternModuleSimulationState's methods outside of ExternModuleSimulation"); - if let WaitTarget::Instant(target) = this.target { - if target < sim.instant { - this.target = WaitTarget::Settle; - } else if yielded_at_all && target == sim.instant { - this.target = WaitTarget::Settle; - } + this.targets.convert_earlier_instants_to_settle(sim.instant); + if this.targets.is_empty() { + this.targets.settle = true; } - if let WaitTarget::Settle = this.target { - if yielded_at_all { + if this.targets.settle { + if this.yielded_at_all { + this.targets.clear(); return Poll::Ready(()); } } - let wait_target = sim.extern_modules[this.module_index] - .wait_target - .get_or_insert(this.target); - *wait_target = (*wait_target).min(this.target); + sim.extern_modules[this.module_index] + .wait_targets + .extend(this.targets.iter()); + this.targets.clear(); + this.yielded_at_all = true; Poll::Pending } } - let target = duration.map_or(WaitTarget::Settle, |duration| { - WaitTarget::Instant(this.borrow().instant + duration) - }); MyGenerator { sim: this, yielded_at_all: false, module_index, - target, + targets, } } - /// returns the next `WaitTarget` and the set of things ready to run then. - fn get_ready_to_run_set(&self, ready_to_run_set: &mut ReadyToRunSet) -> Option { + async fn yield_advance_time_or_settle( + this: Rc>, + module_index: usize, + duration: Option, + ) { + let mut targets = duration.map_or(EarliestWaitTargets::settle(), |duration| { + EarliestWaitTargets::instant(this.borrow().instant + duration) + }); + Self::yield_wait(this, module_index, &mut targets).await; + } + fn is_extern_module_ready_to_run(&mut self, module_index: usize) -> Option { + let module = &self.extern_modules[module_index]; + let mut retval = None; + for wait_target in module.wait_targets.iter() { + retval = match (wait_target, retval) { + (WaitTarget::Settle, _) => Some(self.instant), + (WaitTarget::Instant(instant), _) if instant <= self.instant => Some(self.instant), + (WaitTarget::Instant(instant), None) => Some(instant), + (WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)), + (WaitTarget::Change { key, value }, retval) => { + if Self::value_changed(&mut self.state, key, &value.bits) { + Some(self.instant) + } else { + retval + } + } + }; + if retval == Some(self.instant) { + break; + } + } + retval + } + fn get_ready_to_run_set(&mut self, ready_to_run_set: &mut ReadyToRunSet) -> Option { ready_to_run_set.clear(); - let mut wait_target = None; + let mut retval = None; if self.state_ready_to_run { ready_to_run_set.state_ready_to_run = true; - wait_target = Some(WaitTarget::Settle); + retval = Some(self.instant); } - for (module_index, extern_module) in self.extern_modules.iter().enumerate() { - let Some(extern_module_wait_target) = extern_module.wait_target else { + for module_index in 0..self.extern_modules.len() { + let Some(instant) = self.is_extern_module_ready_to_run(module_index) else { continue; }; - if let Some(wait_target) = &mut wait_target { - match extern_module_wait_target.cmp(wait_target) { + if let Some(retval) = &mut retval { + match instant.cmp(retval) { std::cmp::Ordering::Less => ready_to_run_set.clear(), std::cmp::Ordering::Equal => {} std::cmp::Ordering::Greater => continue, } } else { - wait_target = Some(extern_module_wait_target); + retval = Some(instant); } ready_to_run_set .extern_modules_ready_to_run .push(module_index); } - wait_target + retval } fn set_instant_no_sim(&mut self, instant: SimInstant) { self.instant = instant; @@ -7296,8 +7437,98 @@ impl SimulationImpl { Ok(trace_writer_state) }); } + #[must_use] #[track_caller] - fn run_until(this_ref: &Rc>, run_target: WaitTarget) { + fn run_state_settle_cycle(&mut self) -> bool { + self.state_ready_to_run = false; + self.state.setup_call(0); + if self.breakpoints.is_some() { + loop { + match self + .state + .run(self.breakpoints.as_mut().expect("just checked")) + { + RunResult::Break(break_action) => { + println!( + "hit breakpoint at:\n{:?}", + self.state.debug_insn_at(self.state.pc), + ); + match break_action { + BreakAction::DumpStateAndContinue => { + println!("{self:#?}"); + } + BreakAction::Continue => {} + } + } + RunResult::Return(()) => break, + } + } + } else { + let RunResult::Return(()) = self.state.run(()); + } + if self + .clocks_triggered + .iter() + .any(|i| self.state.small_slots[*i] != 0) + { + self.state_ready_to_run = true; + true + } else { + false + } + } + #[track_caller] + fn run_extern_modules_cycle( + this_ref: &Rc>, + generator_waker: &std::task::Waker, + extern_modules_ready_to_run: &[usize], + ) { + let mut this = this_ref.borrow_mut(); + for module_index in extern_modules_ready_to_run.iter().copied() { + let extern_module = &mut this.extern_modules[module_index]; + extern_module.wait_targets.clear(); + let mut generator = if !extern_module.module_state.did_initial_settle { + let sim = extern_module.sim; + drop(this); + Box::into_pin(sim.run(ExternModuleSimulationState { + sim_impl: this_ref.clone(), + module_index, + wait_for_changes_wait_targets: EarliestWaitTargets::default(), + })) + } else if let Some(generator) = extern_module.running_generator.take() { + drop(this); + generator + } else { + continue; + }; + let generator = match generator + .as_mut() + .poll(&mut std::task::Context::from_waker(generator_waker)) + { + Poll::Ready(()) => None, + Poll::Pending => Some(generator), + }; + this = this_ref.borrow_mut(); + this.extern_modules[module_index] + .module_state + .did_initial_settle = true; + if !this.extern_modules[module_index] + .module_state + .uninitialized_ios + .is_empty() + { + panic!( + "extern module didn't initialize all outputs before \ + waiting, settling, or reading any inputs: {}", + this.extern_modules[module_index].sim.source_location + ); + } + this.extern_modules[module_index].running_generator = generator; + } + } + /// clears `targets` + #[track_caller] + fn run_until(this_ref: &Rc>, run_target: SimInstant) { let mut this = this_ref.borrow_mut(); let mut ready_to_run_set = ReadyToRunSet::default(); let generator_waker = this.generator_waker.clone(); @@ -7305,10 +7536,7 @@ impl SimulationImpl { this.main_module.uninitialized_ios.is_empty(), "didn't initialize all inputs", ); - match run_target { - WaitTarget::Settle => {} - WaitTarget::Instant(run_target) => assert!(run_target >= this.instant), - } + let run_target = run_target.max(this.instant); let mut settle_cycle = 0; let mut run_extern_modules = true; loop { @@ -7318,92 +7546,25 @@ impl SimulationImpl { Some(next_wait_target) if next_wait_target <= run_target => next_wait_target, _ => break, }; - match next_wait_target { - WaitTarget::Settle => {} - WaitTarget::Instant(instant) => { - settle_cycle = 0; - this.set_instant_no_sim(instant); - } + if next_wait_target > this.instant { + settle_cycle = 0; + this.set_instant_no_sim(next_wait_target); } if run_extern_modules { - for module_index in ready_to_run_set.extern_modules_ready_to_run.drain(..) { - let extern_module = &mut this.extern_modules[module_index]; - extern_module.wait_target = None; - let mut generator = if !extern_module.module_state.did_initial_settle { - let sim = extern_module.sim; - drop(this); - Box::into_pin(sim.run(ExternModuleSimulationState { - sim_impl: this_ref.clone(), - module_index, - })) - } else if let Some(generator) = extern_module.running_generator.take() { - drop(this); - generator - } else { - continue; - }; - let generator = match generator - .as_mut() - .poll(&mut std::task::Context::from_waker(&generator_waker)) - { - Poll::Ready(()) => None, - Poll::Pending => Some(generator), - }; - this = this_ref.borrow_mut(); - this.extern_modules[module_index] - .module_state - .did_initial_settle = true; - if !this.extern_modules[module_index] - .module_state - .uninitialized_ios - .is_empty() - { - panic!( - "extern module didn't initialize all outputs before \ - waiting, settling, or reading any inputs: {}", - this.extern_modules[module_index].sim.source_location - ); - } - this.extern_modules[module_index].running_generator = generator; - } + drop(this); + Self::run_extern_modules_cycle( + this_ref, + &generator_waker, + &ready_to_run_set.extern_modules_ready_to_run, + ); + this = this_ref.borrow_mut(); } if ready_to_run_set.state_ready_to_run { - this.state_ready_to_run = false; - run_extern_modules = true; - this.state.setup_call(0); - if this.breakpoints.is_some() { - loop { - let this = &mut *this; - match this - .state - .run(this.breakpoints.as_mut().expect("just checked")) - { - RunResult::Break(break_action) => { - println!( - "hit breakpoint at:\n{:?}", - this.state.debug_insn_at(this.state.pc), - ); - match break_action { - BreakAction::DumpStateAndContinue => { - println!("{this:#?}"); - } - BreakAction::Continue => {} - } - } - RunResult::Return(()) => break, - } - } - } else { - let RunResult::Return(()) = this.state.run(()); - } - if this - .clocks_triggered - .iter() - .any(|i| this.state.small_slots[*i] != 0) - { - this.state_ready_to_run = true; + if this.run_state_settle_cycle() { // wait for clocks to settle before running extern modules again run_extern_modules = false; + } else { + run_extern_modules = true; } } if this.main_module.did_initial_settle { @@ -7434,14 +7595,14 @@ impl SimulationImpl { }); this.state.memory_write_log.clear(); } - match run_target { - WaitTarget::Settle => {} - WaitTarget::Instant(instant) => this.set_instant_no_sim(instant), + if run_target > this.instant { + this.set_instant_no_sim(run_target); } } #[track_caller] fn settle(this_ref: &Rc>) { - Self::run_until(this_ref, WaitTarget::Settle); + let run_target = this_ref.borrow().instant; + Self::run_until(this_ref, run_target); } fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState { match which_module { @@ -7522,12 +7683,13 @@ impl SimulationImpl { } } #[track_caller] - fn read_write_sim_value_helper( + fn read_write_sim_value_helper( state: &mut interpreter::State, compiled_value: CompiledValue, - bits: &mut BitSlice, - read_write_big_scalar: impl Fn(bool, &mut BitSlice, &mut BigInt) + Copy, - read_write_small_scalar: impl Fn(bool, &mut BitSlice, &mut SmallUInt) + Copy, + start_bit_index: usize, + bits: &mut Bits, + read_write_big_scalar: impl Fn(bool, std::ops::Range, &mut Bits, &mut BigInt) + Copy, + read_write_small_scalar: impl Fn(bool, std::ops::Range, &mut Bits, &mut SmallUInt) + Copy, ) { match compiled_value.layout.body { CompiledTypeLayoutBody::Scalar => { @@ -7544,14 +7706,18 @@ impl SimulationImpl { CanonicalType::Clock(_) => false, CanonicalType::PhantomConst(_) => unreachable!(), }; + let bit_indexes = + start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); match compiled_value.range.len() { TypeLen::A_SMALL_SLOT => read_write_small_scalar( signed, + bit_indexes, bits, &mut state.small_slots[compiled_value.range.small_slots.start], ), TypeLen::A_BIG_SLOT => read_write_big_scalar( signed, + bit_indexes, bits, &mut state.big_slots[compiled_value.range.big_slots.start], ), @@ -7571,7 +7737,8 @@ impl SimulationImpl { .index_array(element.layout.len(), element_index), write: None, }, - &mut bits[element_index * element_bit_width..][..element_bit_width], + start_bit_index + element_index * element_bit_width, + bits, read_write_big_scalar, read_write_small_scalar, ); @@ -7580,7 +7747,7 @@ impl SimulationImpl { CompiledTypeLayoutBody::Bundle { fields } => { let ty = Bundle::from_canonical(compiled_value.layout.ty); for ( - (field, offset), + (_field, offset), CompiledBundleField { offset: layout_offset, ty: field_layout, @@ -7597,7 +7764,8 @@ impl SimulationImpl { )), write: None, }, - &mut bits[offset..][..field.ty.bit_width()], + start_bit_index + offset, + bits, read_write_big_scalar, read_write_small_scalar, ); @@ -7606,21 +7774,89 @@ impl SimulationImpl { } } #[track_caller] + fn read_no_settle_helper( + state: &mut interpreter::State, + io: Expr, + compiled_value: CompiledValue, + mut bits: BitVec, + ) -> SimValue { + bits.clear(); + bits.resize(compiled_value.layout.ty.bit_width(), false); + SimulationImpl::read_write_sim_value_helper( + state, + compiled_value, + 0, + &mut bits, + |_signed, bit_range, bits, value| { + ::copy_bits_from_bigint_wrapping(value, &mut bits[bit_range]); + }, + |_signed, bit_range, bits, value| { + let bytes = value.to_le_bytes(); + let bitslice = BitSlice::::from_slice(&bytes); + let bitslice = &bitslice[..bit_range.len()]; + bits[bit_range].clone_from_bitslice(bitslice); + }, + ); + SimValue { + ty: Expr::ty(io), + bits, + } + } + /// doesn't modify `bits` + fn value_changed( + state: &mut interpreter::State, + compiled_value: CompiledValue, + mut bits: &BitSlice, + ) -> bool { + assert_eq!(bits.len(), compiled_value.layout.ty.bit_width()); + let any_change = std::cell::Cell::new(false); + SimulationImpl::read_write_sim_value_helper( + state, + compiled_value, + 0, + &mut bits, + |_signed, bit_range, bits, value| { + if !::bits_equal_bigint_wrapping(value, &bits[bit_range]) { + any_change.set(true); + } + }, + |_signed, bit_range, bits, value| { + let bytes = value.to_le_bytes(); + let bitslice = BitSlice::::from_slice(&bytes); + let bitslice = &bitslice[..bit_range.len()]; + if bits[bit_range] != *bitslice { + any_change.set(true); + } + }, + ); + any_change.get() + } + #[track_caller] fn read( &mut self, io: Expr, which_module: WhichModule, - ) -> MaybeNeedsSettle> { - self.get_module(which_module) - .read_helper(io, which_module) - .map(|compiled_value| ReadFn { compiled_value, io }) - .apply_no_settle(&mut self.state) + ) -> ( + CompiledValue, + MaybeNeedsSettle>, + ) { + let compiled_value = self.get_module(which_module).read_helper(io, which_module); + let value = compiled_value + .map(|compiled_value| ReadFn { + compiled_value, + io, + bits: BitVec::new(), + }) + .apply_no_settle(&mut self.state); + let (MaybeNeedsSettle::NeedsSettle(compiled_value) + | MaybeNeedsSettle::NoSettleNeeded(compiled_value)) = compiled_value; + (compiled_value, value) } #[track_caller] fn write( &mut self, io: Expr, - value: SimValue, + value: &SimValue, which_module: WhichModule, ) { let compiled_value = self @@ -7631,20 +7867,22 @@ impl SimulationImpl { Self::read_write_sim_value_helper( &mut self.state, compiled_value, - &mut value.into_bits(), - |signed, bits, value| { + 0, + &mut value.bits(), + |signed, bit_range, bits, value| { if signed { - *value = SInt::bits_to_bigint(bits); + *value = SInt::bits_to_bigint(&bits[bit_range]); } else { - *value = UInt::bits_to_bigint(bits); + *value = UInt::bits_to_bigint(&bits[bit_range]); } }, - |signed, bits, value| { + |signed, bit_range, bits, value| { let mut small_value = [0; mem::size_of::()]; - if signed && bits.last().as_deref().copied() == Some(true) { + if signed && bits[bit_range.clone()].last().as_deref().copied() == Some(true) { small_value.fill(u8::MAX); } - small_value.view_bits_mut::()[0..bits.len()].clone_from_bitslice(bits); + small_value.view_bits_mut::()[0..bit_range.len()] + .clone_from_bitslice(&bits[bit_range]); *value = SmallUInt::from_le_bytes(small_value); }, ); @@ -7920,14 +8158,14 @@ macro_rules! impl_simulation_methods { let retval = $self .sim_impl .borrow_mut() - .read(Expr::canonical(io), $which_module); + .read(Expr::canonical(io), $which_module).1; SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) } $(#[$track_caller])? pub $($async)? fn write>(&mut $self, io: Expr, value: V) { $self.sim_impl.borrow_mut().write( Expr::canonical(io), - value.into_sim_value(Expr::ty(io)).into_canonical(), + &value.into_sim_value(Expr::ty(io)).into_canonical(), $which_module, ); } @@ -8008,6 +8246,7 @@ impl Simulation { pub struct ExternModuleSimulationState { sim_impl: Rc>, module_index: usize, + wait_for_changes_wait_targets: EarliestWaitTargets, } impl fmt::Debug for ExternModuleSimulationState { @@ -8015,11 +8254,12 @@ impl fmt::Debug for ExternModuleSimulationState { let Self { sim_impl: _, module_index, + wait_for_changes_wait_targets: _, } = self; f.debug_struct("ExternModuleSimulationState") .field("sim_impl", &DebugAsDisplay("...")) .field("module_index", module_index) - .finish() + .finish_non_exhaustive() } } @@ -8036,6 +8276,42 @@ impl ExternModuleSimulationState { ) .await } + pub async fn wait_for_changes>( + &mut self, + iter: I, + timeout: Option, + ) { + self.wait_for_changes_wait_targets.clear(); + let which_module = WhichModule::Extern { + module_index: self.module_index, + }; + for io in iter { + let io = Expr::canonical(io.to_expr()); + let (key, value) = self.sim_impl.borrow_mut().read(io, which_module); + let value = self.settle_if_needed(value).await; + self.wait_for_changes_wait_targets + .insert(WaitTarget::Change { key, value }); + } + if let Some(timeout) = timeout { + self.wait_for_changes_wait_targets.instant = + Some(self.sim_impl.borrow().instant + timeout); + } + SimulationImpl::yield_wait( + self.sim_impl.clone(), + self.module_index, + &mut self.wait_for_changes_wait_targets, + ) + .await; + } + pub async fn wait_for_clock_edge(&mut self, clk: impl ToExpr) { + let clk = clk.to_expr(); + while self.read_clock(clk).await { + self.wait_for_changes([clk], None).await; + } + while !self.read_clock(clk).await { + self.wait_for_changes([clk], None).await; + } + } async fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O where for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index e516f22..6d20715 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -1485,3 +1485,50 @@ fn test_extern_module() { panic!(); } } + +#[hdl_module(outline_generated, extern)] +pub fn extern_module2() { + #[hdl] + let en: Bool = m.input(); + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let o: UInt<8> = m.output(); + m.extern_module_simulation_fn((en, clk, o), |(en, clk, o), mut sim| async move { + for b in "Hello, World!\n".bytes().cycle() { + sim.write(o, b).await; + loop { + sim.wait_for_clock_edge(clk).await; + if sim.read_bool(en).await { + break; + } + } + } + }); +} + +#[test] +fn test_extern_module2() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(extern_module2()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + for i in 0..30 { + sim.write(sim.io().en, i % 10 < 5); + sim.write(sim.io().clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().clk, true); + sim.advance_time(SimDuration::from_micros(1)); + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/extern_module2.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/extern_module2.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt index 23af0b2..6cce70b 100644 --- a/crates/fayalite/tests/sim/expected/extern_module.txt +++ b/crates/fayalite/tests/sim/expected/extern_module.txt @@ -153,11 +153,11 @@ Simulation { running_generator: Some( ..., ), - wait_target: Some( + wait_targets: { Instant( 20.500000000000 μs, ), - ), + }, }, ], state_ready_to_run: false, diff --git a/crates/fayalite/tests/sim/expected/extern_module2.txt b/crates/fayalite/tests/sim/expected/extern_module2.txt new file mode 100644 index 0000000..96710fb --- /dev/null +++ b/crates/fayalite/tests/sim/expected/extern_module2.txt @@ -0,0 +1,308 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 3, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::o", + ty: UInt<8>, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Return, + ], + .. + }, + pc: 0, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [], + }, + big_slots: StatePart { + value: [ + 0, + 1, + 101, + ], + }, + }, + io: Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.en, + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.clk, + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.o, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.clk, + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.en, + Instance { + name: ::extern_module2, + instantiated: Module { + name: extern_module2, + .. + }, + }.o, + }, + did_initial_settle: true, + }, + extern_modules: [ + SimulationExternModuleState { + module_state: SimulationModuleState { + base_targets: [ + ModuleIO { + name: extern_module2::en, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module2::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: extern_module2::o, + is_input: false, + ty: UInt<8>, + .. + }, + ], + uninitialized_ios: {}, + io_targets: { + ModuleIO { + name: extern_module2::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: extern_module2::en, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module2::o, + is_input: false, + ty: UInt<8>, + .. + }, + }, + did_initial_settle: true, + }, + sim: ExternModuleSimulation { + generator: SimGeneratorFn { + args: ( + ModuleIO { + name: extern_module2::en, + is_input: true, + ty: Bool, + .. + }, + ModuleIO { + name: extern_module2::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: extern_module2::o, + is_input: false, + ty: UInt<8>, + .. + }, + ), + f: ..., + }, + source_location: SourceLocation( + module-XXXXXXXXXX.rs:5:1, + ), + }, + running_generator: Some( + ..., + ), + wait_targets: { + Change { + key: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + value: SimValue { + ty: Clock, + bits: 0x1, + }, + }, + }, + }, + ], + state_ready_to_run: false, + trace_decls: TraceModule { + name: "extern_module2", + children: [ + TraceModuleIO { + name: "en", + child: TraceBool { + location: TraceScalarId(0), + name: "en", + flow: Source, + }, + ty: Bool, + flow: Source, + }, + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(1), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceUInt { + location: TraceScalarId(2), + name: "o", + ty: UInt<8>, + flow: Sink, + }, + ty: UInt<8>, + flow: Sink, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigBool { + index: StatePartIndex(0), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigClock { + index: StatePartIndex(1), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<8>, + }, + state: 0x65, + last_state: 0x65, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 60 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module2.vcd b/crates/fayalite/tests/sim/expected/extern_module2.vcd new file mode 100644 index 0000000..464f4bd --- /dev/null +++ b/crates/fayalite/tests/sim/expected/extern_module2.vcd @@ -0,0 +1,150 @@ +$timescale 1 ps $end +$scope module extern_module2 $end +$var wire 1 ! en $end +$var wire 1 " clk $end +$var wire 8 # o $end +$upscope $end +$enddefinitions $end +$dumpvars +1! +0" +b1001000 # +$end +#1000000 +1" +b1100101 # +#2000000 +0" +#3000000 +1" +b1101100 # +#4000000 +0" +#5000000 +1" +#6000000 +0" +#7000000 +1" +b1101111 # +#8000000 +0" +#9000000 +1" +b101100 # +#10000000 +0! +0" +#11000000 +1" +#12000000 +0" +#13000000 +1" +#14000000 +0" +#15000000 +1" +#16000000 +0" +#17000000 +1" +#18000000 +0" +#19000000 +1" +#20000000 +1! +0" +#21000000 +1" +b100000 # +#22000000 +0" +#23000000 +1" +b1010111 # +#24000000 +0" +#25000000 +1" +b1101111 # +#26000000 +0" +#27000000 +1" +b1110010 # +#28000000 +0" +#29000000 +1" +b1101100 # +#30000000 +0! +0" +#31000000 +1" +#32000000 +0" +#33000000 +1" +#34000000 +0" +#35000000 +1" +#36000000 +0" +#37000000 +1" +#38000000 +0" +#39000000 +1" +#40000000 +1! +0" +#41000000 +1" +b1100100 # +#42000000 +0" +#43000000 +1" +b100001 # +#44000000 +0" +#45000000 +1" +b1010 # +#46000000 +0" +#47000000 +1" +b1001000 # +#48000000 +0" +#49000000 +1" +b1100101 # +#50000000 +0! +0" +#51000000 +1" +#52000000 +0" +#53000000 +1" +#54000000 +0" +#55000000 +1" +#56000000 +0" +#57000000 +1" +#58000000 +0" +#59000000 +1" +#60000000 From fdc73b5f3b1d708cded491a1a16292e77a1f3daf Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 25 Mar 2025 18:53:46 -0700 Subject: [PATCH 07/10] add ripple counter test to test simulating alternating circuits and extern modules --- crates/fayalite/tests/sim.rs | 81 + .../tests/sim/expected/ripple_counter.txt | 1492 ++++++++++++++ .../tests/sim/expected/ripple_counter.vcd | 1753 +++++++++++++++++ 3 files changed, 3326 insertions(+) create mode 100644 crates/fayalite/tests/sim/expected/ripple_counter.txt create mode 100644 crates/fayalite/tests/sim/expected/ripple_counter.vcd diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 6d20715..450be54 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -3,6 +3,7 @@ use fayalite::{ int::UIntValue, + module::{instance_with_loc, reg_builder_with_loc}, prelude::*, reset::ResetType, sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, @@ -1532,3 +1533,83 @@ fn test_extern_module2() { panic!(); } } + +// use an extern module to simulate a register to test that the +// simulator can handle chains of alternating circuits and extern modules. +#[hdl_module(outline_generated, extern)] +pub fn sw_reg() { + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let o: Bool = m.output(); + m.extern_module_simulation_fn((clk, o), |(clk, o), mut sim| async move { + let mut state = false; + loop { + sim.write(o, state).await; + sim.wait_for_clock_edge(clk).await; + state = !state; + } + }); +} + +#[hdl_module(outline_generated)] +pub fn ripple_counter() { + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let o: UInt<6> = m.output(); + + #[hdl] + let bits: Array = wire(); + + connect_any(o, bits.cast_to_bits()); + + let mut clk_in = clk; + for (i, bit) in bits.into_iter().enumerate() { + if i % 2 == 0 { + let bit_reg = reg_builder_with_loc(&format!("bit_reg_{i}"), SourceLocation::caller()) + .clock_domain( + #[hdl] + ClockDomain { + clk: clk_in, + rst: false.to_sync_reset(), + }, + ) + .no_reset(Bool) + .build(); + connect(bit, bit_reg); + connect(bit_reg, !bit_reg); + } else { + let bit_reg = + instance_with_loc(&format!("bit_reg_{i}"), sw_reg(), SourceLocation::caller()); + connect(bit_reg.clk, clk_in); + connect(bit, bit_reg.o); + } + clk_in = bit.to_clock(); + } +} + +#[test] +fn test_ripple_counter() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(ripple_counter()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + for _ in 0..0x80 { + sim.write(sim.io().clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().clk, true); + sim.advance_time(SimDuration::from_micros(1)); + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/ripple_counter.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/ripple_counter.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt new file mode 100644 index 0000000..e290ace --- /dev/null +++ b/crates/fayalite/tests/sim/expected/ripple_counter.txt @@ -0,0 +1,1492 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 9, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + big_slots: StatePartLayout { + len: 58, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::o", + ty: UInt<6>, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<3>, + }, + SlotDebugData { + name: "", + ty: UInt<3>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<5>, + }, + SlotDebugData { + name: "", + ty: UInt<5>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<6>, + }, + SlotDebugData { + name: "", + ty: UInt<6>, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", + ty: Bool, + }, + SlotDebugData { + name: ".clk", + ty: Clock, + }, + SlotDebugData { + name: ".rst", + ty: SyncReset, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: SyncReset, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::o", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", + ty: Bool, + }, + SlotDebugData { + name: ".clk", + ty: Clock, + }, + SlotDebugData { + name: ".rst", + ty: SyncReset, + }, + SlotDebugData { + name: "", + ty: Clock, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::o", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", + ty: Bool, + }, + SlotDebugData { + name: ".clk", + ty: Clock, + }, + SlotDebugData { + name: ".rst", + ty: SyncReset, + }, + SlotDebugData { + name: "", + ty: Clock, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::o", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:9:1 + 0: Copy { + dest: StatePartIndex(54), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", ty: Bool }, + src: StatePartIndex(56), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 1: Copy { + dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", ty: Bool }, + src: StatePartIndex(54), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 2: NotU { + dest: StatePartIndex(52), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, + width: 1, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 3: Copy { + dest: StatePartIndex(48), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", ty: Bool }, + src: StatePartIndex(52), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 4: Copy { + dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, + src: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 5: Copy { + dest: StatePartIndex(57), // (0x0) SlotDebugData { name: "", ty: Clock }, + src: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 6: Copy { + dest: StatePartIndex(53), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", ty: Clock }, + src: StatePartIndex(57), // (0x0) SlotDebugData { name: "", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 7: Copy { + dest: StatePartIndex(55), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", ty: Clock }, + src: StatePartIndex(53), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", ty: Clock }, + }, + 8: Copy { + dest: StatePartIndex(43), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", ty: Bool }, + src: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 9: Copy { + dest: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, + src: StatePartIndex(43), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 10: Copy { + dest: StatePartIndex(51), // (0x0) SlotDebugData { name: "", ty: Clock }, + src: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, + }, + 11: NotU { + dest: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, + width: 1, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 12: Copy { + dest: StatePartIndex(37), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", ty: Bool }, + src: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 13: Copy { + dest: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, + src: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 14: Copy { + dest: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Clock }, + src: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 15: Copy { + dest: StatePartIndex(42), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", ty: Clock }, + src: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 16: Copy { + dest: StatePartIndex(44), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", ty: Clock }, + src: StatePartIndex(42), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", ty: Clock }, + }, + 17: Copy { + dest: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", ty: Bool }, + src: StatePartIndex(34), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 18: Copy { + dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, + src: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 19: Copy { + dest: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Clock }, + src: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, + }, + 20: NotU { + dest: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, + width: 1, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 21: Copy { + dest: StatePartIndex(25), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", ty: Bool }, + src: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 22: Copy { + dest: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, + src: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 23: Copy { + dest: StatePartIndex(35), // (0x0) SlotDebugData { name: "", ty: Clock }, + src: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 24: Copy { + dest: StatePartIndex(31), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", ty: Clock }, + src: StatePartIndex(35), // (0x0) SlotDebugData { name: "", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 25: Copy { + dest: StatePartIndex(33), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", ty: Clock }, + src: StatePartIndex(31), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 26: Const { + dest: StatePartIndex(28), // (0x0) SlotDebugData { name: "", ty: Bool }, + value: 0x0, + }, + 27: Copy { + dest: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, + src: StatePartIndex(28), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + 28: Copy { + dest: StatePartIndex(26), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, + src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::clk", ty: Clock }, + }, + 29: Copy { + dest: StatePartIndex(27), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, + src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 30: IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(26), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, + }, + 31: 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 + 32: Copy { + dest: StatePartIndex(38), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, + src: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Clock }, + }, + 33: Copy { + dest: StatePartIndex(39), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, + src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 34: IsNonZeroDestIsSmall { + dest: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(38), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, + }, + 35: AndSmall { + dest: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 36: Copy { + dest: StatePartIndex(49), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, + src: StatePartIndex(51), // (0x0) SlotDebugData { name: "", ty: Clock }, + }, + 37: Copy { + dest: StatePartIndex(50), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, + src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 38: IsNonZeroDestIsSmall { + dest: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(49), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, + }, + 39: AndSmall { + dest: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(6), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 40: Copy { + dest: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", ty: Bool }, + }, + 41: Shl { + dest: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + lhs: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 5, + }, + 42: Copy { + dest: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, + }, + 43: Shl { + dest: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, + lhs: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 4, + }, + 44: Copy { + dest: StatePartIndex(15), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, + }, + 45: Shl { + dest: StatePartIndex(16), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(15), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 3, + }, + 46: Copy { + dest: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, + }, + 47: Shl { + dest: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + lhs: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 2, + }, + 48: Copy { + dest: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, + }, + 49: Shl { + dest: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 1, + }, + 50: Copy { + dest: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, + }, + 51: Or { + dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, + rhs: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + }, + 52: Or { + dest: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + lhs: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + }, + 53: Or { + dest: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + rhs: StatePartIndex(16), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + }, + 54: Or { + dest: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, + lhs: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + rhs: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, + }, + 55: Or { + dest: StatePartIndex(23), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + lhs: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, + rhs: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 56: Copy { + dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::o", ty: UInt<6> }, + src: StatePartIndex(23), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 57: BranchIfSmallZero { + target: 59, + value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 58: Copy { + dest: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, + src: StatePartIndex(25), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", ty: Bool }, + }, + 59: BranchIfSmallZero { + target: 61, + value: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 60: Copy { + dest: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, + src: StatePartIndex(37), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", ty: Bool }, + }, + 61: BranchIfSmallZero { + target: 63, + value: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 62: Copy { + dest: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, + src: StatePartIndex(48), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", ty: Bool }, + }, + 63: XorSmallImmediate { + dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: 0x1, + }, + 64: XorSmallImmediate { + dest: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + rhs: 0x1, + }, + 65: XorSmallImmediate { + dest: StatePartIndex(6), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + rhs: 0x1, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 66: Return, + ], + .. + }, + pc: 66, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + ], + }, + big_slots: StatePart { + value: [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + ], + }, + }, + io: Instance { + name: ::ripple_counter, + instantiated: Module { + name: ripple_counter, + .. + }, + }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::ripple_counter, + instantiated: Module { + name: ripple_counter, + .. + }, + }.clk, + Instance { + name: ::ripple_counter, + instantiated: Module { + name: ripple_counter, + .. + }, + }.o, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::ripple_counter, + instantiated: Module { + name: ripple_counter, + .. + }, + }.clk, + Instance { + name: ::ripple_counter, + instantiated: Module { + name: ripple_counter, + .. + }, + }.o, + }, + did_initial_settle: true, + }, + extern_modules: [ + SimulationExternModuleState { + module_state: SimulationModuleState { + base_targets: [ + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ], + uninitialized_ios: {}, + io_targets: { + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + }, + did_initial_settle: true, + }, + sim: ExternModuleSimulation { + generator: SimGeneratorFn { + args: ( + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ), + f: ..., + }, + source_location: SourceLocation( + module-XXXXXXXXXX-2.rs:4:1, + ), + }, + running_generator: Some( + ..., + ), + wait_targets: { + Change { + key: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 3, len: 0 }, + big_slots: StatePartIndexRange { start: 33, len: 1 }, + }, + write: None, + }, + value: SimValue { + ty: Clock, + bits: 0x0, + }, + }, + }, + }, + SimulationExternModuleState { + module_state: SimulationModuleState { + base_targets: [ + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ], + uninitialized_ios: {}, + io_targets: { + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + }, + did_initial_settle: true, + }, + sim: ExternModuleSimulation { + generator: SimGeneratorFn { + args: ( + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ), + f: ..., + }, + source_location: SourceLocation( + module-XXXXXXXXXX-2.rs:4:1, + ), + }, + running_generator: Some( + ..., + ), + wait_targets: { + Change { + key: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 6, len: 0 }, + big_slots: StatePartIndexRange { start: 44, len: 1 }, + }, + write: None, + }, + value: SimValue { + ty: Clock, + bits: 0x0, + }, + }, + }, + }, + SimulationExternModuleState { + module_state: SimulationModuleState { + base_targets: [ + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ], + uninitialized_ios: {}, + io_targets: { + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + }, + did_initial_settle: true, + }, + sim: ExternModuleSimulation { + generator: SimGeneratorFn { + args: ( + ModuleIO { + name: sw_reg::clk, + is_input: true, + ty: Clock, + .. + }, + ModuleIO { + name: sw_reg::o, + is_input: false, + ty: Bool, + .. + }, + ), + f: ..., + }, + source_location: SourceLocation( + module-XXXXXXXXXX-2.rs:4:1, + ), + }, + running_generator: Some( + ..., + ), + wait_targets: { + Change { + key: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 9, len: 0 }, + big_slots: StatePartIndexRange { start: 55, len: 1 }, + }, + write: None, + }, + value: SimValue { + ty: Clock, + bits: 0x0, + }, + }, + }, + }, + ], + state_ready_to_run: false, + trace_decls: TraceModule { + name: "ripple_counter", + children: [ + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(0), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceUInt { + location: TraceScalarId(1), + name: "o", + ty: UInt<6>, + flow: Sink, + }, + ty: UInt<6>, + flow: Sink, + }, + TraceWire { + name: "bits", + child: TraceArray { + name: "bits", + elements: [ + TraceBool { + location: TraceScalarId(2), + name: "[0]", + flow: Duplex, + }, + TraceBool { + location: TraceScalarId(3), + name: "[1]", + flow: Duplex, + }, + TraceBool { + location: TraceScalarId(4), + name: "[2]", + flow: Duplex, + }, + TraceBool { + location: TraceScalarId(5), + name: "[3]", + flow: Duplex, + }, + TraceBool { + location: TraceScalarId(6), + name: "[4]", + flow: Duplex, + }, + TraceBool { + location: TraceScalarId(7), + name: "[5]", + flow: Duplex, + }, + ], + ty: Array, + flow: Duplex, + }, + ty: Array, + }, + TraceReg { + name: "bit_reg_0", + child: TraceBool { + location: TraceScalarId(8), + name: "bit_reg_0", + flow: Duplex, + }, + ty: Bool, + }, + TraceInstance { + name: "bit_reg_1", + instance_io: TraceBundle { + name: "bit_reg_1", + fields: [ + TraceClock { + location: TraceScalarId(11), + name: "clk", + flow: Sink, + }, + TraceBool { + location: TraceScalarId(12), + name: "o", + flow: Source, + }, + ], + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + flow: Source, + }, + module: TraceModule { + name: "sw_reg", + children: [ + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(9), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceBool { + location: TraceScalarId(10), + name: "o", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + ], + }, + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + }, + TraceReg { + name: "bit_reg_2", + child: TraceBool { + location: TraceScalarId(13), + name: "bit_reg_2", + flow: Duplex, + }, + ty: Bool, + }, + TraceInstance { + name: "bit_reg_3", + instance_io: TraceBundle { + name: "bit_reg_3", + fields: [ + TraceClock { + location: TraceScalarId(16), + name: "clk", + flow: Sink, + }, + TraceBool { + location: TraceScalarId(17), + name: "o", + flow: Source, + }, + ], + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + flow: Source, + }, + module: TraceModule { + name: "sw_reg", + children: [ + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(14), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceBool { + location: TraceScalarId(15), + name: "o", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + ], + }, + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + }, + TraceReg { + name: "bit_reg_4", + child: TraceBool { + location: TraceScalarId(18), + name: "bit_reg_4", + flow: Duplex, + }, + ty: Bool, + }, + TraceInstance { + name: "bit_reg_5", + instance_io: TraceBundle { + name: "bit_reg_5", + fields: [ + TraceClock { + location: TraceScalarId(21), + name: "clk", + flow: Sink, + }, + TraceBool { + location: TraceScalarId(22), + name: "o", + flow: Source, + }, + ], + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + flow: Source, + }, + module: TraceModule { + name: "sw_reg", + children: [ + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(19), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "o", + child: TraceBool { + location: TraceScalarId(20), + name: "o", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + ], + }, + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + o: Bool, + }, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigClock { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(1), + ty: UInt<6>, + }, + state: 0x00, + last_state: 0x00, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigBool { + index: StatePartIndex(2), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigBool { + index: StatePartIndex(3), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigBool { + index: StatePartIndex(4), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigBool { + index: StatePartIndex(5), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigBool { + index: StatePartIndex(6), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigBool { + index: StatePartIndex(7), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(8), + kind: BigBool { + index: StatePartIndex(24), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(9), + kind: BigClock { + index: StatePartIndex(33), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(10), + kind: BigBool { + index: StatePartIndex(34), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(11), + kind: BigClock { + index: StatePartIndex(31), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(12), + kind: BigBool { + index: StatePartIndex(32), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(13), + kind: BigBool { + index: StatePartIndex(36), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(14), + kind: BigClock { + index: StatePartIndex(44), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(15), + kind: BigBool { + index: StatePartIndex(45), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(16), + kind: BigClock { + index: StatePartIndex(42), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(17), + kind: BigBool { + index: StatePartIndex(43), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(18), + kind: BigBool { + index: StatePartIndex(47), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(19), + kind: BigClock { + index: StatePartIndex(55), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(20), + kind: BigBool { + index: StatePartIndex(56), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(21), + kind: BigClock { + index: StatePartIndex(53), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(22), + kind: BigBool { + index: StatePartIndex(54), + }, + state: 0x0, + last_state: 0x0, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 256 μs, + clocks_triggered: [ + StatePartIndex(1), + StatePartIndex(4), + StatePartIndex(7), + ], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.vcd b/crates/fayalite/tests/sim/expected/ripple_counter.vcd new file mode 100644 index 0000000..6f14a8e --- /dev/null +++ b/crates/fayalite/tests/sim/expected/ripple_counter.vcd @@ -0,0 +1,1753 @@ +$timescale 1 ps $end +$scope module ripple_counter $end +$var wire 1 ! clk $end +$var wire 6 " o $end +$scope struct bits $end +$var wire 1 # \[0] $end +$var wire 1 $ \[1] $end +$var wire 1 % \[2] $end +$var wire 1 & \[3] $end +$var wire 1 ' \[4] $end +$var wire 1 ( \[5] $end +$upscope $end +$var reg 1 ) bit_reg_0 $end +$scope struct bit_reg_1 $end +$var wire 1 , clk $end +$var wire 1 - o $end +$upscope $end +$scope module sw_reg $end +$var wire 1 * clk $end +$var wire 1 + o $end +$upscope $end +$var reg 1 . bit_reg_2 $end +$scope struct bit_reg_3 $end +$var wire 1 1 clk $end +$var wire 1 2 o $end +$upscope $end +$scope module sw_reg_2 $end +$var wire 1 / clk $end +$var wire 1 0 o $end +$upscope $end +$var reg 1 3 bit_reg_4 $end +$scope struct bit_reg_5 $end +$var wire 1 6 clk $end +$var wire 1 7 o $end +$upscope $end +$scope module sw_reg_3 $end +$var wire 1 4 clk $end +$var wire 1 5 o $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +b0 " +0# +0$ +0% +0& +0' +0( +0) +0* +0+ +0, +0- +0. +0/ +00 +01 +02 +03 +04 +05 +06 +07 +$end +#1000000 +1! +1) +b1 " +1# +1* +1, +1+ +b11 " +1$ +1- +1. +b111 " +1% +1/ +11 +10 +b1111 " +1& +12 +13 +b11111 " +1' +14 +16 +15 +b111111 " +1( +17 +#2000000 +0! +#3000000 +1! +0) +b111110 " +0# +0* +0, +#4000000 +0! +#5000000 +1! +1) +b111111 " +1# +1* +1, +0+ +b111101 " +0$ +0- +#6000000 +0! +#7000000 +1! +0) +b111100 " +0# +0* +0, +#8000000 +0! +#9000000 +1! +1) +b111101 " +1# +1* +1, +1+ +b111111 " +1$ +1- +0. +b111011 " +0% +0/ +01 +#10000000 +0! +#11000000 +1! +0) +b111010 " +0# +0* +0, +#12000000 +0! +#13000000 +1! +1) +b111011 " +1# +1* +1, +0+ +b111001 " +0$ +0- +#14000000 +0! +#15000000 +1! +0) +b111000 " +0# +0* +0, +#16000000 +0! +#17000000 +1! +1) +b111001 " +1# +1* +1, +1+ +b111011 " +1$ +1- +1. +b111111 " +1% +1/ +11 +00 +b110111 " +0& +02 +#18000000 +0! +#19000000 +1! +0) +b110110 " +0# +0* +0, +#20000000 +0! +#21000000 +1! +1) +b110111 " +1# +1* +1, +0+ +b110101 " +0$ +0- +#22000000 +0! +#23000000 +1! +0) +b110100 " +0# +0* +0, +#24000000 +0! +#25000000 +1! +1) +b110101 " +1# +1* +1, +1+ +b110111 " +1$ +1- +0. +b110011 " +0% +0/ +01 +#26000000 +0! +#27000000 +1! +0) +b110010 " +0# +0* +0, +#28000000 +0! +#29000000 +1! +1) +b110011 " +1# +1* +1, +0+ +b110001 " +0$ +0- +#30000000 +0! +#31000000 +1! +0) +b110000 " +0# +0* +0, +#32000000 +0! +#33000000 +1! +1) +b110001 " +1# +1* +1, +1+ +b110011 " +1$ +1- +1. +b110111 " +1% +1/ +11 +10 +b111111 " +1& +12 +03 +b101111 " +0' +04 +06 +#34000000 +0! +#35000000 +1! +0) +b101110 " +0# +0* +0, +#36000000 +0! +#37000000 +1! +1) +b101111 " +1# +1* +1, +0+ +b101101 " +0$ +0- +#38000000 +0! +#39000000 +1! +0) +b101100 " +0# +0* +0, +#40000000 +0! +#41000000 +1! +1) +b101101 " +1# +1* +1, +1+ +b101111 " +1$ +1- +0. +b101011 " +0% +0/ +01 +#42000000 +0! +#43000000 +1! +0) +b101010 " +0# +0* +0, +#44000000 +0! +#45000000 +1! +1) +b101011 " +1# +1* +1, +0+ +b101001 " +0$ +0- +#46000000 +0! +#47000000 +1! +0) +b101000 " +0# +0* +0, +#48000000 +0! +#49000000 +1! +1) +b101001 " +1# +1* +1, +1+ +b101011 " +1$ +1- +1. +b101111 " +1% +1/ +11 +00 +b100111 " +0& +02 +#50000000 +0! +#51000000 +1! +0) +b100110 " +0# +0* +0, +#52000000 +0! +#53000000 +1! +1) +b100111 " +1# +1* +1, +0+ +b100101 " +0$ +0- +#54000000 +0! +#55000000 +1! +0) +b100100 " +0# +0* +0, +#56000000 +0! +#57000000 +1! +1) +b100101 " +1# +1* +1, +1+ +b100111 " +1$ +1- +0. +b100011 " +0% +0/ +01 +#58000000 +0! +#59000000 +1! +0) +b100010 " +0# +0* +0, +#60000000 +0! +#61000000 +1! +1) +b100011 " +1# +1* +1, +0+ +b100001 " +0$ +0- +#62000000 +0! +#63000000 +1! +0) +b100000 " +0# +0* +0, +#64000000 +0! +#65000000 +1! +1) +b100001 " +1# +1* +1, +1+ +b100011 " +1$ +1- +1. +b100111 " +1% +1/ +11 +10 +b101111 " +1& +12 +13 +b111111 " +1' +14 +16 +05 +b11111 " +0( +07 +#66000000 +0! +#67000000 +1! +0) +b11110 " +0# +0* +0, +#68000000 +0! +#69000000 +1! +1) +b11111 " +1# +1* +1, +0+ +b11101 " +0$ +0- +#70000000 +0! +#71000000 +1! +0) +b11100 " +0# +0* +0, +#72000000 +0! +#73000000 +1! +1) +b11101 " +1# +1* +1, +1+ +b11111 " +1$ +1- +0. +b11011 " +0% +0/ +01 +#74000000 +0! +#75000000 +1! +0) +b11010 " +0# +0* +0, +#76000000 +0! +#77000000 +1! +1) +b11011 " +1# +1* +1, +0+ +b11001 " +0$ +0- +#78000000 +0! +#79000000 +1! +0) +b11000 " +0# +0* +0, +#80000000 +0! +#81000000 +1! +1) +b11001 " +1# +1* +1, +1+ +b11011 " +1$ +1- +1. +b11111 " +1% +1/ +11 +00 +b10111 " +0& +02 +#82000000 +0! +#83000000 +1! +0) +b10110 " +0# +0* +0, +#84000000 +0! +#85000000 +1! +1) +b10111 " +1# +1* +1, +0+ +b10101 " +0$ +0- +#86000000 +0! +#87000000 +1! +0) +b10100 " +0# +0* +0, +#88000000 +0! +#89000000 +1! +1) +b10101 " +1# +1* +1, +1+ +b10111 " +1$ +1- +0. +b10011 " +0% +0/ +01 +#90000000 +0! +#91000000 +1! +0) +b10010 " +0# +0* +0, +#92000000 +0! +#93000000 +1! +1) +b10011 " +1# +1* +1, +0+ +b10001 " +0$ +0- +#94000000 +0! +#95000000 +1! +0) +b10000 " +0# +0* +0, +#96000000 +0! +#97000000 +1! +1) +b10001 " +1# +1* +1, +1+ +b10011 " +1$ +1- +1. +b10111 " +1% +1/ +11 +10 +b11111 " +1& +12 +03 +b1111 " +0' +04 +06 +#98000000 +0! +#99000000 +1! +0) +b1110 " +0# +0* +0, +#100000000 +0! +#101000000 +1! +1) +b1111 " +1# +1* +1, +0+ +b1101 " +0$ +0- +#102000000 +0! +#103000000 +1! +0) +b1100 " +0# +0* +0, +#104000000 +0! +#105000000 +1! +1) +b1101 " +1# +1* +1, +1+ +b1111 " +1$ +1- +0. +b1011 " +0% +0/ +01 +#106000000 +0! +#107000000 +1! +0) +b1010 " +0# +0* +0, +#108000000 +0! +#109000000 +1! +1) +b1011 " +1# +1* +1, +0+ +b1001 " +0$ +0- +#110000000 +0! +#111000000 +1! +0) +b1000 " +0# +0* +0, +#112000000 +0! +#113000000 +1! +1) +b1001 " +1# +1* +1, +1+ +b1011 " +1$ +1- +1. +b1111 " +1% +1/ +11 +00 +b111 " +0& +02 +#114000000 +0! +#115000000 +1! +0) +b110 " +0# +0* +0, +#116000000 +0! +#117000000 +1! +1) +b111 " +1# +1* +1, +0+ +b101 " +0$ +0- +#118000000 +0! +#119000000 +1! +0) +b100 " +0# +0* +0, +#120000000 +0! +#121000000 +1! +1) +b101 " +1# +1* +1, +1+ +b111 " +1$ +1- +0. +b11 " +0% +0/ +01 +#122000000 +0! +#123000000 +1! +0) +b10 " +0# +0* +0, +#124000000 +0! +#125000000 +1! +1) +b11 " +1# +1* +1, +0+ +b1 " +0$ +0- +#126000000 +0! +#127000000 +1! +0) +b0 " +0# +0* +0, +#128000000 +0! +#129000000 +1! +1) +b1 " +1# +1* +1, +1+ +b11 " +1$ +1- +1. +b111 " +1% +1/ +11 +10 +b1111 " +1& +12 +13 +b11111 " +1' +14 +16 +15 +b111111 " +1( +17 +#130000000 +0! +#131000000 +1! +0) +b111110 " +0# +0* +0, +#132000000 +0! +#133000000 +1! +1) +b111111 " +1# +1* +1, +0+ +b111101 " +0$ +0- +#134000000 +0! +#135000000 +1! +0) +b111100 " +0# +0* +0, +#136000000 +0! +#137000000 +1! +1) +b111101 " +1# +1* +1, +1+ +b111111 " +1$ +1- +0. +b111011 " +0% +0/ +01 +#138000000 +0! +#139000000 +1! +0) +b111010 " +0# +0* +0, +#140000000 +0! +#141000000 +1! +1) +b111011 " +1# +1* +1, +0+ +b111001 " +0$ +0- +#142000000 +0! +#143000000 +1! +0) +b111000 " +0# +0* +0, +#144000000 +0! +#145000000 +1! +1) +b111001 " +1# +1* +1, +1+ +b111011 " +1$ +1- +1. +b111111 " +1% +1/ +11 +00 +b110111 " +0& +02 +#146000000 +0! +#147000000 +1! +0) +b110110 " +0# +0* +0, +#148000000 +0! +#149000000 +1! +1) +b110111 " +1# +1* +1, +0+ +b110101 " +0$ +0- +#150000000 +0! +#151000000 +1! +0) +b110100 " +0# +0* +0, +#152000000 +0! +#153000000 +1! +1) +b110101 " +1# +1* +1, +1+ +b110111 " +1$ +1- +0. +b110011 " +0% +0/ +01 +#154000000 +0! +#155000000 +1! +0) +b110010 " +0# +0* +0, +#156000000 +0! +#157000000 +1! +1) +b110011 " +1# +1* +1, +0+ +b110001 " +0$ +0- +#158000000 +0! +#159000000 +1! +0) +b110000 " +0# +0* +0, +#160000000 +0! +#161000000 +1! +1) +b110001 " +1# +1* +1, +1+ +b110011 " +1$ +1- +1. +b110111 " +1% +1/ +11 +10 +b111111 " +1& +12 +03 +b101111 " +0' +04 +06 +#162000000 +0! +#163000000 +1! +0) +b101110 " +0# +0* +0, +#164000000 +0! +#165000000 +1! +1) +b101111 " +1# +1* +1, +0+ +b101101 " +0$ +0- +#166000000 +0! +#167000000 +1! +0) +b101100 " +0# +0* +0, +#168000000 +0! +#169000000 +1! +1) +b101101 " +1# +1* +1, +1+ +b101111 " +1$ +1- +0. +b101011 " +0% +0/ +01 +#170000000 +0! +#171000000 +1! +0) +b101010 " +0# +0* +0, +#172000000 +0! +#173000000 +1! +1) +b101011 " +1# +1* +1, +0+ +b101001 " +0$ +0- +#174000000 +0! +#175000000 +1! +0) +b101000 " +0# +0* +0, +#176000000 +0! +#177000000 +1! +1) +b101001 " +1# +1* +1, +1+ +b101011 " +1$ +1- +1. +b101111 " +1% +1/ +11 +00 +b100111 " +0& +02 +#178000000 +0! +#179000000 +1! +0) +b100110 " +0# +0* +0, +#180000000 +0! +#181000000 +1! +1) +b100111 " +1# +1* +1, +0+ +b100101 " +0$ +0- +#182000000 +0! +#183000000 +1! +0) +b100100 " +0# +0* +0, +#184000000 +0! +#185000000 +1! +1) +b100101 " +1# +1* +1, +1+ +b100111 " +1$ +1- +0. +b100011 " +0% +0/ +01 +#186000000 +0! +#187000000 +1! +0) +b100010 " +0# +0* +0, +#188000000 +0! +#189000000 +1! +1) +b100011 " +1# +1* +1, +0+ +b100001 " +0$ +0- +#190000000 +0! +#191000000 +1! +0) +b100000 " +0# +0* +0, +#192000000 +0! +#193000000 +1! +1) +b100001 " +1# +1* +1, +1+ +b100011 " +1$ +1- +1. +b100111 " +1% +1/ +11 +10 +b101111 " +1& +12 +13 +b111111 " +1' +14 +16 +05 +b11111 " +0( +07 +#194000000 +0! +#195000000 +1! +0) +b11110 " +0# +0* +0, +#196000000 +0! +#197000000 +1! +1) +b11111 " +1# +1* +1, +0+ +b11101 " +0$ +0- +#198000000 +0! +#199000000 +1! +0) +b11100 " +0# +0* +0, +#200000000 +0! +#201000000 +1! +1) +b11101 " +1# +1* +1, +1+ +b11111 " +1$ +1- +0. +b11011 " +0% +0/ +01 +#202000000 +0! +#203000000 +1! +0) +b11010 " +0# +0* +0, +#204000000 +0! +#205000000 +1! +1) +b11011 " +1# +1* +1, +0+ +b11001 " +0$ +0- +#206000000 +0! +#207000000 +1! +0) +b11000 " +0# +0* +0, +#208000000 +0! +#209000000 +1! +1) +b11001 " +1# +1* +1, +1+ +b11011 " +1$ +1- +1. +b11111 " +1% +1/ +11 +00 +b10111 " +0& +02 +#210000000 +0! +#211000000 +1! +0) +b10110 " +0# +0* +0, +#212000000 +0! +#213000000 +1! +1) +b10111 " +1# +1* +1, +0+ +b10101 " +0$ +0- +#214000000 +0! +#215000000 +1! +0) +b10100 " +0# +0* +0, +#216000000 +0! +#217000000 +1! +1) +b10101 " +1# +1* +1, +1+ +b10111 " +1$ +1- +0. +b10011 " +0% +0/ +01 +#218000000 +0! +#219000000 +1! +0) +b10010 " +0# +0* +0, +#220000000 +0! +#221000000 +1! +1) +b10011 " +1# +1* +1, +0+ +b10001 " +0$ +0- +#222000000 +0! +#223000000 +1! +0) +b10000 " +0# +0* +0, +#224000000 +0! +#225000000 +1! +1) +b10001 " +1# +1* +1, +1+ +b10011 " +1$ +1- +1. +b10111 " +1% +1/ +11 +10 +b11111 " +1& +12 +03 +b1111 " +0' +04 +06 +#226000000 +0! +#227000000 +1! +0) +b1110 " +0# +0* +0, +#228000000 +0! +#229000000 +1! +1) +b1111 " +1# +1* +1, +0+ +b1101 " +0$ +0- +#230000000 +0! +#231000000 +1! +0) +b1100 " +0# +0* +0, +#232000000 +0! +#233000000 +1! +1) +b1101 " +1# +1* +1, +1+ +b1111 " +1$ +1- +0. +b1011 " +0% +0/ +01 +#234000000 +0! +#235000000 +1! +0) +b1010 " +0# +0* +0, +#236000000 +0! +#237000000 +1! +1) +b1011 " +1# +1* +1, +0+ +b1001 " +0$ +0- +#238000000 +0! +#239000000 +1! +0) +b1000 " +0# +0* +0, +#240000000 +0! +#241000000 +1! +1) +b1001 " +1# +1* +1, +1+ +b1011 " +1$ +1- +1. +b1111 " +1% +1/ +11 +00 +b111 " +0& +02 +#242000000 +0! +#243000000 +1! +0) +b110 " +0# +0* +0, +#244000000 +0! +#245000000 +1! +1) +b111 " +1# +1* +1, +0+ +b101 " +0$ +0- +#246000000 +0! +#247000000 +1! +0) +b100 " +0# +0* +0, +#248000000 +0! +#249000000 +1! +1) +b101 " +1# +1* +1, +1+ +b111 " +1$ +1- +0. +b11 " +0% +0/ +01 +#250000000 +0! +#251000000 +1! +0) +b10 " +0# +0* +0, +#252000000 +0! +#253000000 +1! +1) +b11 " +1# +1* +1, +0+ +b1 " +0$ +0- +#254000000 +0! +#255000000 +1! +0) +b0 " +0# +0* +0, +#256000000 From ec3a61513ba0b3a4b8db7026bac7bc6beb0a1eaa Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 27 Mar 2025 23:03:44 -0700 Subject: [PATCH 08/10] simulator read/write types must be passive --- crates/fayalite/src/sim.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 275b106..b508756 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -6698,6 +6698,11 @@ impl SimulationModuleState { mut target: Target, which_module: WhichModule, ) -> CompiledValue { + assert!( + target.canonical_ty().is_passive(), + "simulator read/write expression must have a passive type \ + (recursively contains no fields with `#[hdl(flip)]`)" + ); if let Some(&retval) = self.io_targets.get(&target) { return retval; } From e0f978fbb6b9ce19876489d0bbe5fcdae57175a3 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 27 Mar 2025 23:17:28 -0700 Subject: [PATCH 09/10] silence unused `m` variable warning in #[hdl_module] with an empty body. --- crates/fayalite-proc-macros-impl/src/module.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/fayalite-proc-macros-impl/src/module.rs b/crates/fayalite-proc-macros-impl/src/module.rs index 0852f58..62b7837 100644 --- a/crates/fayalite-proc-macros-impl/src/module.rs +++ b/crates/fayalite-proc-macros-impl/src/module.rs @@ -377,7 +377,7 @@ impl ModuleFn { module_kind, vis, sig, - block, + mut block, struct_generics, the_struct, } = match self.0 { @@ -439,6 +439,12 @@ impl ModuleFn { body_sig .inputs .insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder }); + block.stmts.insert( + 0, + parse_quote! { + let _ = m; + }, + ); let body_fn = ItemFn { attrs: vec![], vis: Visibility::Inherited, From 5028401a5adad671f31ab754a958a692debdb062 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 27 Mar 2025 23:44:36 -0700 Subject: [PATCH 10/10] change SimValue to contain and deref to a value and not just contain bits --- .../src/hdl_bundle.rs | 171 ++++- .../fayalite-proc-macros-impl/src/hdl_enum.rs | 269 +++++++ crates/fayalite/src/array.rs | 55 ++ crates/fayalite/src/bundle.rs | 191 ++++- crates/fayalite/src/clock.rs | 17 + crates/fayalite/src/enum_.rs | 327 ++++++++- crates/fayalite/src/expr.rs | 1 + crates/fayalite/src/int.rs | 68 +- crates/fayalite/src/lib.rs | 2 + crates/fayalite/src/phantom_const.rs | 23 + crates/fayalite/src/reset.rs | 17 + crates/fayalite/src/sim.rs | 674 +----------------- crates/fayalite/src/sim/value.rs | 665 +++++++++++++++++ crates/fayalite/src/ty.rs | 52 +- crates/fayalite/src/util.rs | 1 + crates/fayalite/src/util/alternating_cell.rs | 122 ++++ crates/fayalite/tests/sim.rs | 214 +++--- .../tests/sim/expected/extern_module2.txt | 4 +- .../tests/sim/expected/ripple_counter.txt | 12 +- 19 files changed, 2065 insertions(+), 820 deletions(-) create mode 100644 crates/fayalite/src/sim/value.rs create mode 100644 crates/fayalite/src/util/alternating_cell.rs diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index b0fe498..a083def 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -30,7 +30,9 @@ pub(crate) struct ParsedBundle { pub(crate) field_flips: Vec>>, pub(crate) mask_type_ident: Ident, pub(crate) mask_type_match_variant_ident: Ident, + pub(crate) mask_type_sim_value_ident: Ident, pub(crate) match_variant_ident: Ident, + pub(crate) sim_value_ident: Ident, pub(crate) builder_ident: Ident, pub(crate) mask_type_builder_ident: Ident, } @@ -125,7 +127,9 @@ impl ParsedBundle { field_flips, mask_type_ident: format_ident!("__{}__MaskType", ident), mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident), + mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident), match_variant_ident: format_ident!("__{}__MatchVariant", ident), + sim_value_ident: format_ident!("__{}__SimValue", ident), mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident), builder_ident: format_ident!("__{}__Builder", ident), ident, @@ -427,7 +431,9 @@ impl ToTokens for ParsedBundle { field_flips, mask_type_ident, mask_type_match_variant_ident, + mask_type_sim_value_ident, match_variant_ident, + sim_value_ident, builder_ident, mask_type_builder_ident, } = self; @@ -523,7 +529,7 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); - let mut mask_type_match_variant_fields = mask_type_fields; + let mut mask_type_match_variant_fields = mask_type_fields.clone(); for Field { ty, .. } in &mut mask_type_match_variant_fields.named { *ty = parse_quote_spanned! {span=> ::fayalite::expr::Expr<#ty> @@ -565,6 +571,58 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); + let mut mask_type_sim_value_fields = mask_type_fields; + for Field { ty, .. } in &mut mask_type_sim_value_fields.named { + *ty = parse_quote_spanned! {span=> + ::fayalite::sim::value::SimValue<#ty> + }; + } + ItemStruct { + attrs: vec![ + parse_quote_spanned! {span=> + #[::fayalite::__std::prelude::v1::derive( + ::fayalite::__std::fmt::Debug, + ::fayalite::__std::clone::Clone, + )] + }, + parse_quote_spanned! {span=> + #[allow(non_camel_case_types, dead_code)] + }, + ], + vis: vis.clone(), + struct_token: *struct_token, + ident: mask_type_sim_value_ident.clone(), + generics: generics.into(), + fields: Fields::Named(mask_type_sim_value_fields), + semi_token: None, + } + .to_tokens(tokens); + let mut sim_value_fields = FieldsNamed::from(fields.clone()); + for Field { ty, .. } in &mut sim_value_fields.named { + *ty = parse_quote_spanned! {span=> + ::fayalite::sim::value::SimValue<#ty> + }; + } + ItemStruct { + attrs: vec![ + parse_quote_spanned! {span=> + #[::fayalite::__std::prelude::v1::derive( + ::fayalite::__std::fmt::Debug, + ::fayalite::__std::clone::Clone, + )] + }, + parse_quote_spanned! {span=> + #[allow(non_camel_case_types, dead_code)] + }, + ], + vis: vis.clone(), + struct_token: *struct_token, + ident: sim_value_ident.clone(), + generics: generics.into(), + fields: Fields::Named(sim_value_fields), + semi_token: None, + } + .to_tokens(tokens); let this_token = Ident::new("__this", span); let fields_token = Ident::new("__fields", span); let self_token = Token![self](span); @@ -615,6 +673,25 @@ impl ToTokens for ParsedBundle { } }, )); + let sim_value_from_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { + let ident: &Ident = field.ident().as_ref().unwrap(); + quote_spanned! {span=> + #ident: v.field_from_bits(), + } + })); + let sim_value_clone_from_bits_fields = + Vec::from_iter(fields.named().into_iter().map(|field| { + let ident: &Ident = field.ident().as_ref().unwrap(); + quote_spanned! {span=> + v.field_clone_from_bits(&mut value.#ident); + } + })); + let sim_value_to_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { + let ident: &Ident = field.ident().as_ref().unwrap(); + quote_spanned! {span=> + v.field_to_bits(&value.#ident); + } + })); let fields_len = fields.named().into_iter().len(); quote_spanned! {span=> #[automatically_derived] @@ -623,6 +700,7 @@ impl ToTokens for ParsedBundle { { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; + type SimValue = #mask_type_sim_value_ident #type_generics; type MatchVariant = #mask_type_match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -660,6 +738,34 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } + fn sim_value_from_bits( + &self, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) -> ::SimValue { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); + #mask_type_sim_value_ident { + #(#sim_value_from_bits_fields)* + } + } + fn sim_value_clone_from_bits( + &self, + value: &mut ::SimValue, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); + #(#sim_value_clone_from_bits_fields)* + } + fn sim_value_to_bits( + &self, + value: &::SimValue, + bits: &mut ::fayalite::__bitvec::slice::BitSlice, + ) { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); + #(#sim_value_to_bits_fields)* + } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics @@ -696,6 +802,7 @@ impl ToTokens for ParsedBundle { { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; + type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -735,6 +842,34 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } + fn sim_value_from_bits( + &self, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) -> ::SimValue { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); + #sim_value_ident { + #(#sim_value_from_bits_fields)* + } + } + fn sim_value_clone_from_bits( + &self, + value: &mut ::SimValue, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); + #(#sim_value_clone_from_bits_fields)* + } + fn sim_value_to_bits( + &self, + value: &::SimValue, + bits: &mut ::fayalite::__bitvec::slice::BitSlice, + ) { + #![allow(unused_mut, unused_variables)] + let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); + #(#sim_value_to_bits_fields)* + } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics @@ -768,23 +903,33 @@ impl ToTokens for ParsedBundle { } .to_tokens(tokens); if let Some((cmp_eq,)) = cmp_eq { - let mut where_clause = + let mut expr_where_clause = Generics::from(generics) .where_clause .unwrap_or_else(|| syn::WhereClause { where_token: Token![where](span), predicates: Punctuated::new(), }); + let mut sim_value_where_clause = expr_where_clause.clone(); + let mut fields_sim_value_eq = vec![]; let mut fields_cmp_eq = vec![]; let mut fields_cmp_ne = vec![]; for field in fields.named() { let field_ident = field.ident(); let field_ty = field.ty(); - where_clause + expr_where_clause .predicates .push(parse_quote_spanned! {cmp_eq.span=> #field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty> }); + sim_value_where_clause + .predicates + .push(parse_quote_spanned! {cmp_eq.span=> + #field_ty: ::fayalite::sim::value::SimValuePartialEq<#field_ty> + }); + fields_sim_value_eq.push(quote_spanned! {span=> + ::fayalite::sim::value::SimValuePartialEq::sim_value_eq(&__lhs.#field_ident, &__rhs.#field_ident) + }); fields_cmp_eq.push(quote_spanned! {span=> ::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident) }); @@ -792,9 +937,13 @@ impl ToTokens for ParsedBundle { ::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident) }); } + let sim_value_eq_body; let cmp_eq_body; let cmp_ne_body; if fields_len == 0 { + sim_value_eq_body = quote_spanned! {span=> + true + }; cmp_eq_body = quote_spanned! {span=> ::fayalite::expr::ToExpr::to_expr(&true) }; @@ -802,6 +951,9 @@ impl ToTokens for ParsedBundle { ::fayalite::expr::ToExpr::to_expr(&false) }; } else { + sim_value_eq_body = quote_spanned! {span=> + #(#fields_sim_value_eq)&&* + }; cmp_eq_body = quote_spanned! {span=> #(#fields_cmp_eq)&* }; @@ -812,7 +964,7 @@ impl ToTokens for ParsedBundle { quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::expr::ops::ExprPartialEq for #target #type_generics - #where_clause + #expr_where_clause { fn cmp_eq( __lhs: ::fayalite::expr::Expr, @@ -827,6 +979,17 @@ impl ToTokens for ParsedBundle { #cmp_ne_body } } + #[automatically_derived] + impl #impl_generics ::fayalite::sim::value::SimValuePartialEq for #target #type_generics + #sim_value_where_clause + { + fn sim_value_eq( + __lhs: &::fayalite::sim::value::SimValue, + __rhs: &::fayalite::sim::value::SimValue, + ) -> bool { + #sim_value_eq_body + } + } } .to_tokens(tokens); } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index 9174566..0cdf85c 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -129,6 +129,7 @@ pub(crate) struct ParsedEnum { pub(crate) brace_token: Brace, pub(crate) variants: Punctuated, pub(crate) match_variant_ident: Ident, + pub(crate) sim_value_ident: Ident, } impl ParsedEnum { @@ -190,6 +191,7 @@ impl ParsedEnum { brace_token, variants, match_variant_ident: format_ident!("__{}__MatchVariant", ident), + sim_value_ident: format_ident!("__{}__SimValue", ident), ident, }) } @@ -207,6 +209,7 @@ impl ToTokens for ParsedEnum { brace_token, variants, match_variant_ident, + sim_value_ident, } = self; let span = ident.span(); let ItemOptions { @@ -409,6 +412,106 @@ impl ToTokens for ParsedEnum { )), } .to_tokens(tokens); + let mut enum_attrs = attrs.clone(); + enum_attrs.push(parse_quote_spanned! {span=> + #[::fayalite::__std::prelude::v1::derive( + ::fayalite::__std::fmt::Debug, + ::fayalite::__std::clone::Clone, + )] + }); + enum_attrs.push(parse_quote_spanned! {span=> + #[allow(dead_code, non_camel_case_types)] + }); + let sim_value_has_unknown_variant = !variants.len().is_power_of_two(); + let sim_value_unknown_variant_name = sim_value_has_unknown_variant.then(|| { + let mut name = String::new(); + let unknown = "Unknown"; + loop { + let orig_len = name.len(); + name.push_str(unknown); + if variants.iter().all(|v| v.ident != name) { + break Ident::new(&name, span); + } + name.truncate(orig_len); + name.push('_'); + } + }); + let sim_value_unknown_variant = + sim_value_unknown_variant_name + .as_ref() + .map(|unknown_variant_name| { + Pair::End(parse_quote_spanned! {span=> + #unknown_variant_name(::fayalite::enum_::UnknownVariantSimValue) + }) + }); + ItemEnum { + attrs: enum_attrs, + vis: vis.clone(), + enum_token: *enum_token, + ident: sim_value_ident.clone(), + generics: generics.into(), + brace_token: *brace_token, + variants: Punctuated::from_iter( + variants + .pairs() + .map_pair_value_ref( + |ParsedVariant { + attrs, + options: _, + ident, + field, + }| Variant { + attrs: attrs.clone(), + ident: ident.clone(), + fields: match field { + Some(ParsedVariantField { + paren_token, + attrs, + options: _, + ty, + comma_token, + }) => Fields::Unnamed(FieldsUnnamed { + paren_token: *paren_token, + unnamed: Punctuated::from_iter([ + Pair::new( + Field { + attrs: attrs.clone(), + vis: Visibility::Inherited, + mutability: FieldMutability::None, + ident: None, + colon_token: None, + ty: parse_quote_spanned! {span=> + ::fayalite::sim::value::SimValue<#ty> + }, + }, + Some(comma_token.unwrap_or(Token![,](ident.span()))), + ), + Pair::new( + Field { + attrs: vec![], + vis: Visibility::Inherited, + mutability: FieldMutability::None, + ident: None, + colon_token: None, + ty: parse_quote_spanned! {span=> + ::fayalite::enum_::EnumPaddingSimValue + }, + }, + None, + ), + ]), + }), + None => Fields::Unnamed(parse_quote_spanned! {span=> + (::fayalite::enum_::EnumPaddingSimValue) + }), + }, + discriminant: None, + }, + ) + .chain(sim_value_unknown_variant), + ), + } + .to_tokens(tokens); let self_token = Token![self](span); for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() { if let Some(ParsedVariantField { ty, .. }) = field { @@ -534,6 +637,142 @@ impl ToTokens for ParsedEnum { } }, )); + let sim_value_from_bits_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = + &sim_value_unknown_variant_name + { + quote_spanned! {span=> + _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_bits()), + } + } else { + quote_spanned! {span=> + _ => ::fayalite::__std::unreachable!(), + } + }; + let sim_value_from_bits_match_arms = Vec::from_iter( + variants + .iter() + .enumerate() + .map( + |( + index, + ParsedVariant { + attrs: _, + options: _, + ident, + field, + }, + )| { + if let Some(_) = field { + quote_spanned! {span=> + #index => { + let (field, padding) = v.variant_with_field_from_bits(); + #sim_value_ident::#ident(field, padding) + } + } + } else { + quote_spanned! {span=> + #index => #sim_value_ident::#ident( + v.variant_no_field_from_bits(), + ), + } + } + }, + ) + .chain([sim_value_from_bits_unknown_match_arm]), + ); + let sim_value_clone_from_bits_unknown_match_arm = + if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { + quote_spanned! {span=> + _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { + v.unknown_variant_clone_from_bits(value); + } else { + *value = #sim_value_ident::#sim_value_unknown_variant_name( + v.unknown_variant_from_bits(), + ); + }, + } + } else { + quote_spanned! {span=> + _ => ::fayalite::__std::unreachable!(), + } + }; + let sim_value_clone_from_bits_match_arms = Vec::from_iter( + variants + .iter() + .enumerate() + .map( + |( + index, + ParsedVariant { + attrs: _, + options: _, + ident, + field, + }, + )| { + if let Some(_) = field { + quote_spanned! {span=> + #index => if let #sim_value_ident::#ident(field, padding) = value { + v.variant_with_field_clone_from_bits(field, padding); + } else { + let (field, padding) = v.variant_with_field_from_bits(); + *value = #sim_value_ident::#ident(field, padding); + }, + } + } else { + quote_spanned! {span=> + #index => if let #sim_value_ident::#ident(padding) = value { + v.variant_no_field_clone_from_bits(padding); + } else { + *value = #sim_value_ident::#ident( + v.variant_no_field_from_bits(), + ); + }, + } + } + }, + ) + .chain([sim_value_clone_from_bits_unknown_match_arm]), + ); + let sim_value_to_bits_match_arms = Vec::from_iter( + variants + .iter() + .enumerate() + .map( + |( + index, + ParsedVariant { + attrs: _, + options: _, + ident, + field, + }, + )| { + if let Some(_) = field { + quote_spanned! {span=> + #sim_value_ident::#ident(field, padding) => { + v.variant_with_field_to_bits(#index, field, padding); + } + } + } else { + quote_spanned! {span=> + #sim_value_ident::#ident(padding) => { + v.variant_no_field_to_bits(#index, padding); + } + } + } + }, + ) + .chain(sim_value_unknown_variant_name.as_ref().map( + |sim_value_unknown_variant_name| { + quote_spanned! {span=> + #sim_value_ident::#sim_value_unknown_variant_name(value) => { + v.unknown_variant_to_bits(value); + } + } + }, + )), + ); let variants_len = variants.len(); quote_spanned! {span=> #[automatically_derived] @@ -542,6 +781,7 @@ impl ToTokens for ParsedEnum { { type BaseType = ::fayalite::enum_::Enum; type MaskType = ::fayalite::int::Bool; + type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = ::fayalite::module::Scope; type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope; @@ -574,6 +814,35 @@ impl ToTokens for ParsedEnum { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } + fn sim_value_from_bits( + &self, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) -> ::SimValue { + let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); + match v.discriminant() { + #(#sim_value_from_bits_match_arms)* + } + } + fn sim_value_clone_from_bits( + &self, + value: &mut ::SimValue, + bits: &::fayalite::__bitvec::slice::BitSlice, + ) { + let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); + match v.discriminant() { + #(#sim_value_clone_from_bits_match_arms)* + } + } + fn sim_value_to_bits( + &self, + value: &::SimValue, + bits: &mut ::fayalite::__bitvec::slice::BitSlice, + ) { + let v = ::fayalite::enum_::EnumSimValueToBits::new(*self, bits); + match value { + #(#sim_value_to_bits_match_arms)* + } + } } #[automatically_derived] impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 0d9b63f..a2df6cf 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +use bitvec::slice::BitSlice; + use crate::{ expr::{ ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq}, @@ -9,6 +11,7 @@ use crate::{ int::{Bool, DynSize, KnownSize, Size, SizeType, DYN_SIZE}, intern::{Intern, Interned, LazyInterned}, module::transform::visit::{Fold, Folder, Visit, Visitor}, + sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, ty::{ CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, @@ -142,6 +145,7 @@ impl, Len: Size, State: Visitor + ?Sized> Visit impl Type for ArrayType { type BaseType = Array; type MaskType = ArrayType; + type SimValue = Len::ArraySimValue; type MatchVariant = Len::ArrayMatch; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope>; @@ -178,9 +182,48 @@ impl Type for ArrayType { Len::from_usize(array.len()), ) } + fn source_location() -> SourceLocation { SourceLocation::builtin() } + + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), self.type_properties.bit_width); + let element = self.element(); + let element_bit_width = element.canonical().bit_width(); + TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| { + SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width]) + }))) + .ok() + .expect("used correct length") + } + + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), self.type_properties.bit_width); + let element_ty = self.element(); + let element_bit_width = element_ty.canonical().bit_width(); + let value: &mut [SimValue] = value.as_mut(); + assert_eq!(self.len(), value.len()); + for (i, element_value) in value.iter_mut().enumerate() { + assert_eq!(SimValue::ty(element_value), element_ty); + SimValue::bits_mut(element_value) + .bits_mut() + .copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]); + } + } + + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), self.type_properties.bit_width); + let element_ty = self.element(); + let element_bit_width = element_ty.canonical().bit_width(); + let value: &[SimValue] = value.as_ref(); + assert_eq!(self.len(), value.len()); + for (i, element_value) in value.iter().enumerate() { + assert_eq!(SimValue::ty(element_value), element_ty); + bits[i * element_bit_width..][..element_bit_width] + .copy_from_bitslice(SimValue::bits(element_value).bits()); + } + } } impl TypeWithDeref for ArrayType { @@ -247,6 +290,18 @@ where } } +impl SimValuePartialEq> for ArrayType +where + Lhs: SimValuePartialEq, +{ + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + AsRef::<[_]>::as_ref(&**this) + .iter() + .zip(AsRef::<[_]>::as_ref(&**other)) + .all(|(l, r)| SimValuePartialEq::sim_value_eq(l, r)) + } +} + impl ExprIntoIterator for ArrayType { type Item = T; type ExprIntoIter = ExprArrayIter; diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 9807b92..06e0411 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -8,14 +8,14 @@ use crate::{ }, int::{Bool, DynSize}, intern::{Intern, Interned}, - sim::{SimValue, ToSimValue}, + sim::value::{SimValue, SimValuePartialEq, ToSimValue}, source_location::SourceLocation, ty::{ - impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type, - TypeProperties, TypeWithDeref, + impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, + StaticType, Type, TypeProperties, TypeWithDeref, }, }; -use bitvec::vec::BitVec; +use bitvec::{slice::BitSlice, vec::BitVec}; use hashbrown::HashMap; use std::{fmt, marker::PhantomData}; @@ -216,6 +216,7 @@ impl Bundle { impl Type for Bundle { type BaseType = Bundle; type MaskType = Bundle; + type SimValue = OpaqueSimValue; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Self::new(Interned::from_iter(self.0.fields.into_iter().map( @@ -239,6 +240,20 @@ impl Type for Bundle { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), self.type_properties().bit_width); + OpaqueSimValue::from_bitslice(bits) + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), self.type_properties().bit_width); + assert_eq!(value.bit_width(), self.type_properties().bit_width); + value.bits_mut().bits_mut().copy_from_bitslice(bits); + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), self.type_properties().bit_width); + assert_eq!(value.bit_width(), self.type_properties().bit_width); + bits.copy_from_bitslice(value.bits().bits()); + } } pub trait BundleType: Type { @@ -247,6 +262,93 @@ pub trait BundleType: Type { fn fields(&self) -> Interned<[BundleField]>; } +pub struct BundleSimValueFromBits<'a> { + fields: std::slice::Iter<'static, BundleField>, + bits: &'a BitSlice, +} + +impl<'a> BundleSimValueFromBits<'a> { + #[track_caller] + pub fn new(bundle_ty: T, bits: &'a BitSlice) -> Self { + let fields = bundle_ty.fields(); + assert_eq!( + bits.len(), + fields + .iter() + .map(|BundleField { ty, .. }| ty.bit_width()) + .sum::() + ); + Self { + fields: Interned::into_inner(fields).iter(), + bits, + } + } + #[track_caller] + fn field_ty_and_bits(&mut self) -> (T, &'a BitSlice) { + let Some(&BundleField { + name: _, + flipped: _, + ty, + }) = self.fields.next() + else { + panic!("tried to read too many fields from BundleSimValueFromBits"); + }; + let (field_bits, rest) = self.bits.split_at(ty.bit_width()); + self.bits = rest; + (T::from_canonical(ty), field_bits) + } + #[track_caller] + pub fn field_from_bits(&mut self) -> SimValue { + let (field_ty, field_bits) = self.field_ty_and_bits::(); + SimValue::from_bitslice(field_ty, field_bits) + } + #[track_caller] + pub fn field_clone_from_bits(&mut self, field_value: &mut SimValue) { + let (field_ty, field_bits) = self.field_ty_and_bits::(); + assert_eq!(field_ty, SimValue::ty(field_value)); + SimValue::bits_mut(field_value) + .bits_mut() + .copy_from_bitslice(field_bits); + } +} + +pub struct BundleSimValueToBits<'a> { + fields: std::slice::Iter<'static, BundleField>, + bits: &'a mut BitSlice, +} + +impl<'a> BundleSimValueToBits<'a> { + #[track_caller] + pub fn new(bundle_ty: T, bits: &'a mut BitSlice) -> Self { + let fields = bundle_ty.fields(); + assert_eq!( + bits.len(), + fields + .iter() + .map(|BundleField { ty, .. }| ty.bit_width()) + .sum::() + ); + Self { + fields: Interned::into_inner(fields).iter(), + bits, + } + } + #[track_caller] + pub fn field_to_bits(&mut self, field_value: &SimValue) { + let Some(&BundleField { + name: _, + flipped: _, + ty, + }) = self.fields.next() + else { + panic!("tried to read too many fields from BundleSimValueFromBits"); + }; + assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); + self.bits[..ty.bit_width()].copy_from_bitslice(SimValue::bits(field_value).bits()); + self.bits = &mut std::mem::take(&mut self.bits)[ty.bit_width()..]; + } +} + #[derive(Default)] pub struct NoBuilder; @@ -353,6 +455,7 @@ macro_rules! impl_tuples { impl<$($T: Type,)*> Type for ($($T,)*) { type BaseType = Bundle; type MaskType = ($($T::MaskType,)*); + type SimValue = ($(SimValue<$T>,)*); type MatchVariant = ($(Expr<$T>,)*); type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -391,6 +494,24 @@ macro_rules! impl_tuples { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + #![allow(unused_mut, unused_variables)] + let mut v = BundleSimValueFromBits::new(*self, bits); + $(let $var = v.field_from_bits();)* + ($($var,)*) + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + #![allow(unused_mut, unused_variables)] + let mut v = BundleSimValueFromBits::new(*self, bits); + let ($($var,)*) = value; + $(v.field_clone_from_bits($var);)* + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + #![allow(unused_mut, unused_variables)] + let mut v = BundleSimValueToBits::new(*self, bits); + let ($($var,)*) = value; + $(v.field_to_bits($var);)* + } } impl<$($T: Type,)*> BundleType for ($($T,)*) { type Builder = TupleBuilder<($(Unfilled<$T>,)*)>; @@ -444,16 +565,12 @@ macro_rules! impl_tuples { impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { #[track_caller] fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - ToSimValue::::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical() + SimValue::into_canonical(ToSimValue::::to_sim_value(self, Bundle::from_canonical(ty))) } #[track_caller] fn into_sim_value(self, ty: CanonicalType) -> SimValue { - ToSimValue::::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { - ToSimValue::::box_into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() + SimValue::into_canonical(ToSimValue::::into_sim_value(self, Bundle::from_canonical(ty))) } } impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { @@ -474,24 +591,12 @@ macro_rules! impl_tuples { let [$($ty_var,)*] = *ty.fields() else { panic!("bundle has wrong number of fields"); }; - let mut bits: Option = None; + let mut bits = BitVec::new(); $(let $var = $var.into_sim_value($ty_var.ty); - assert_eq!($var.ty(), $ty_var.ty); - if !$var.bits().is_empty() { - if let Some(bits) = &mut bits { - bits.extend_from_bitslice($var.bits()); - } else { - let mut $var = $var.into_bits(); - $var.reserve(ty.type_properties().bit_width - $var.len()); - bits = Some($var); - } - } + assert_eq!(SimValue::ty(&$var), $ty_var.ty); + bits.extend_from_bitslice(SimValue::bits(&$var).bits()); )* - bits.unwrap_or_else(BitVec::new).into_sim_value(ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: Bundle) -> SimValue { - Self::into_sim_value(*self, ty) + bits.into_sim_value(ty) } } impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) { @@ -499,19 +604,15 @@ macro_rules! impl_tuples { fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { let ($($var,)*) = self; let ($($ty_var,)*) = ty; - $(let $var = $var.to_sim_value($ty_var).into_canonical();)* - SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) + $(let $var = $var.to_sim_value($ty_var);)* + SimValue::from_value(ty, ($($var,)*)) } #[track_caller] fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { let ($($var,)*) = self; let ($($ty_var,)*) = ty; - $(let $var = $var.into_sim_value($ty_var).into_canonical();)* - SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { - Self::into_sim_value(*self, ty) + $(let $var = $var.into_sim_value($ty_var);)* + SimValue::from_value(ty, ($($var,)*)) } } impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { @@ -537,6 +638,15 @@ macro_rules! impl_tuples { .any_one_bits() } } + impl<$($Lhs: SimValuePartialEq<$Rhs>, $Rhs: Type,)*> SimValuePartialEq<($($Rhs,)*)> for ($($Lhs,)*) { + fn sim_value_eq(lhs: &SimValue, rhs: &SimValue<($($Rhs,)*)>) -> bool { + let ($($lhs_var,)*) = &**lhs; + let ($($rhs_var,)*) = &**rhs; + let retval = true; + $(let retval = retval && $lhs_var == $rhs_var;)* + retval + } + } }; ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { impl_tuples!([$($lhs)*] []); @@ -564,6 +674,7 @@ impl_tuples! { impl Type for PhantomData { type BaseType = Bundle; type MaskType = (); + type SimValue = (); type MatchVariant = PhantomData; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -596,6 +707,16 @@ impl Type for PhantomData { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert!(bits.is_empty()); + () + } + fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { + assert!(bits.is_empty()); + } + fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { + assert!(bits.is_empty()); + } } pub struct PhantomDataBuilder(PhantomData); @@ -663,6 +784,6 @@ impl ToSimValue for PhantomData { fn to_sim_value(&self, ty: CanonicalType) -> SimValue { let ty = Bundle::from_canonical(ty); assert!(ty.fields().is_empty()); - ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical() + SimValue::into_canonical(ToSimValue::into_sim_value(BitVec::new(), ty)) } } diff --git a/crates/fayalite/src/clock.rs b/crates/fayalite/src/clock.rs index 711432b..f0623d4 100644 --- a/crates/fayalite/src/clock.rs +++ b/crates/fayalite/src/clock.rs @@ -8,6 +8,7 @@ use crate::{ source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; +use bitvec::slice::BitSlice; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct Clock; @@ -15,6 +16,7 @@ pub struct Clock; impl Type for Clock { type BaseType = Clock; type MaskType = Bool; + type SimValue = bool; impl_match_variant_as_self!(); @@ -36,6 +38,21 @@ impl Type for Clock { }; retval } + + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), 1); + bits[0] + } + + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), 1); + *value = bits[0]; + } + + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), 1); + bits.set(0, *value); + } } impl Clock { diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 70c58c0..9fa38e9 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -7,17 +7,22 @@ use crate::{ Expr, ToExpr, }, hdl, - int::Bool, + int::{Bool, UIntValue}, intern::{Intern, Interned}, module::{ connect, enum_match_variants_helper, incomplete_wire, wire, EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, }, + sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, - ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties}, + ty::{ + CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type, + TypeProperties, + }, }; +use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; use hashbrown::HashMap; -use std::{convert::Infallible, fmt, iter::FusedIterator}; +use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct EnumVariant { @@ -152,6 +157,12 @@ impl EnumTypePropertiesBuilder { variant_count: variant_count + 1, } } + #[must_use] + pub fn variants(self, variants: impl IntoIterator) -> Self { + variants.into_iter().fold(self, |this, variant| { + this.variant(variant.ty.map(CanonicalType::type_properties)) + }) + } pub const fn finish(self) -> TypeProperties { assert!( self.variant_count != 0, @@ -325,6 +336,7 @@ impl EnumType for Enum { impl Type for Enum { type BaseType = Enum; type MaskType = Bool; + type SimValue = OpaqueSimValue; type MatchVariant = Option>; type MatchActiveScope = Scope; type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope; @@ -355,6 +367,296 @@ impl Type for Enum { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), self.type_properties().bit_width); + OpaqueSimValue::from_bitslice(bits) + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), self.type_properties().bit_width); + assert_eq!(value.bit_width(), self.type_properties().bit_width); + value.bits_mut().bits_mut().copy_from_bitslice(bits); + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), self.type_properties().bit_width); + assert_eq!(value.bit_width(), self.type_properties().bit_width); + bits.copy_from_bitslice(value.bits().bits()); + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] +pub struct EnumPaddingSimValue { + bits: Option, +} + +impl EnumPaddingSimValue { + pub fn bit_width(&self) -> Option { + self.bits.as_ref().map(UIntValue::width) + } + pub fn bits(&self) -> &Option { + &self.bits + } + pub fn bits_mut(&mut self) -> &mut Option { + &mut self.bits + } + pub fn into_bits(self) -> Option { + self.bits + } + pub fn from_bits(bits: Option) -> Self { + Self { bits } + } + pub fn from_bitslice(v: &BitSlice) -> Self { + Self { + bits: Some(UIntValue::new(Arc::new(v.to_bitvec()))), + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct UnknownVariantSimValue { + discriminant: usize, + body_bits: UIntValue, +} + +impl UnknownVariantSimValue { + pub fn discriminant(&self) -> usize { + self.discriminant + } + pub fn body_bits(&self) -> &UIntValue { + &self.body_bits + } + pub fn body_bits_mut(&mut self) -> &mut UIntValue { + &mut self.body_bits + } + pub fn into_body_bits(self) -> UIntValue { + self.body_bits + } + pub fn into_parts(self) -> (usize, UIntValue) { + (self.discriminant, self.body_bits) + } + pub fn new(discriminant: usize, body_bits: UIntValue) -> Self { + Self { + discriminant, + body_bits, + } + } +} + +pub struct EnumSimValueFromBits<'a> { + variants: Interned<[EnumVariant]>, + discriminant: usize, + body_bits: &'a BitSlice, +} + +impl<'a> EnumSimValueFromBits<'a> { + #[track_caller] + pub fn new(ty: T, bits: &'a BitSlice) -> Self { + let variants = ty.variants(); + let bit_width = EnumTypePropertiesBuilder::new() + .variants(variants) + .finish() + .bit_width; + assert_eq!(bit_width, bits.len()); + let (discriminant_bits, body_bits) = + bits.split_at(discriminant_bit_width_impl(variants.len())); + let mut discriminant = 0usize; + discriminant.view_bits_mut::()[..discriminant_bits.len()] + .copy_from_bitslice(discriminant_bits); + Self { + variants, + discriminant, + body_bits, + } + } + pub fn discriminant(&self) -> usize { + self.discriminant + } + #[track_caller] + #[cold] + fn usage_error(&self, clone: bool) -> ! { + let clone = if clone { "clone_" } else { "" }; + match self.variants.get(self.discriminant) { + None => { + panic!("should have called EnumSimValueFromBits::unknown_variant_{clone}from_bits"); + } + Some(EnumVariant { ty: None, .. }) => { + panic!( + "should have called EnumSimValueFromBits::variant_no_field_{clone}from_bits" + ); + } + Some(EnumVariant { ty: Some(_), .. }) => { + panic!( + "should have called EnumSimValueFromBits::variant_with_field_{clone}from_bits" + ); + } + } + } + #[track_caller] + fn known_variant(&self, clone: bool) -> (Option, &'a BitSlice, &'a BitSlice) { + let Some(EnumVariant { ty, .. }) = self.variants.get(self.discriminant) else { + self.usage_error(clone); + }; + let variant_bit_width = ty.map_or(0, CanonicalType::bit_width); + let (variant_bits, padding_bits) = self.body_bits.split_at(variant_bit_width); + (*ty, variant_bits, padding_bits) + } + #[track_caller] + pub fn unknown_variant_from_bits(self) -> UnknownVariantSimValue { + let None = self.variants.get(self.discriminant) else { + self.usage_error(false); + }; + UnknownVariantSimValue::new( + self.discriminant, + UIntValue::new(Arc::new(self.body_bits.to_bitvec())), + ) + } + #[track_caller] + pub fn unknown_variant_clone_from_bits(self, value: &mut UnknownVariantSimValue) { + let None = self.variants.get(self.discriminant) else { + self.usage_error(true); + }; + value.discriminant = self.discriminant; + assert_eq!(value.body_bits.width(), self.body_bits.len()); + value + .body_bits + .bits_mut() + .copy_from_bitslice(self.body_bits); + } + #[track_caller] + pub fn variant_no_field_from_bits(self) -> EnumPaddingSimValue { + let (None, _variant_bits, padding_bits) = self.known_variant(false) else { + self.usage_error(false); + }; + EnumPaddingSimValue::from_bitslice(padding_bits) + } + #[track_caller] + pub fn variant_with_field_from_bits(self) -> (SimValue, EnumPaddingSimValue) { + let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { + self.usage_error(false); + }; + ( + SimValue::from_bitslice(T::from_canonical(variant_ty), variant_bits), + EnumPaddingSimValue::from_bitslice(padding_bits), + ) + } + #[track_caller] + fn clone_padding_from_bits(padding: &mut EnumPaddingSimValue, padding_bits: &BitSlice) { + match padding.bits_mut() { + None => *padding = EnumPaddingSimValue::from_bitslice(padding_bits), + Some(padding) => { + assert_eq!(padding.width(), padding_bits.len()); + padding.bits_mut().copy_from_bitslice(padding_bits); + } + } + } + #[track_caller] + pub fn variant_no_field_clone_from_bits(self, padding: &mut EnumPaddingSimValue) { + let (None, _variant_bits, padding_bits) = self.known_variant(true) else { + self.usage_error(true); + }; + Self::clone_padding_from_bits(padding, padding_bits); + } + #[track_caller] + pub fn variant_with_field_clone_from_bits( + self, + value: &mut SimValue, + padding: &mut EnumPaddingSimValue, + ) { + let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else { + self.usage_error(true); + }; + assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); + SimValue::bits_mut(value) + .bits_mut() + .copy_from_bitslice(variant_bits); + Self::clone_padding_from_bits(padding, padding_bits); + } +} + +pub struct EnumSimValueToBits<'a> { + variants: Interned<[EnumVariant]>, + bit_width: usize, + discriminant_bit_width: usize, + bits: &'a mut BitSlice, +} + +impl<'a> EnumSimValueToBits<'a> { + #[track_caller] + pub fn new(ty: T, bits: &'a mut BitSlice) -> Self { + let variants = ty.variants(); + let bit_width = EnumTypePropertiesBuilder::new() + .variants(variants) + .finish() + .bit_width; + assert_eq!(bit_width, bits.len()); + Self { + variants, + bit_width, + discriminant_bit_width: discriminant_bit_width_impl(variants.len()), + bits, + } + } + #[track_caller] + fn discriminant_to_bits(&mut self, mut discriminant: usize) { + let orig_discriminant = discriminant; + let discriminant_bits = + &mut discriminant.view_bits_mut::()[..self.discriminant_bit_width]; + self.bits[..self.discriminant_bit_width].copy_from_bitslice(discriminant_bits); + discriminant_bits.fill(false); + assert!( + discriminant == 0, + "{orig_discriminant:#x} is too big to fit in enum discriminant bits", + ); + } + #[track_caller] + pub fn unknown_variant_to_bits(mut self, value: &UnknownVariantSimValue) { + self.discriminant_to_bits(value.discriminant); + let None = self.variants.get(value.discriminant) else { + panic!("can't use UnknownVariantSimValue to set known discriminant"); + }; + assert_eq!( + self.bit_width - self.discriminant_bit_width, + value.body_bits.width() + ); + self.bits[self.discriminant_bit_width..].copy_from_bitslice(value.body_bits.bits()); + } + #[track_caller] + fn known_variant( + mut self, + discriminant: usize, + padding: &EnumPaddingSimValue, + ) -> (Option, &'a mut BitSlice) { + self.discriminant_to_bits(discriminant); + let variant_ty = self.variants[discriminant].ty; + let variant_bit_width = variant_ty.map_or(0, CanonicalType::bit_width); + let padding_bits = &mut self.bits[self.discriminant_bit_width..][variant_bit_width..]; + if let Some(padding) = padding.bits() { + assert_eq!(padding.width(), padding_bits.len()); + padding_bits.copy_from_bitslice(padding.bits()); + } else { + padding_bits.fill(false); + } + let variant_bits = &mut self.bits[self.discriminant_bit_width..][..variant_bit_width]; + (variant_ty, variant_bits) + } + #[track_caller] + pub fn variant_no_field_to_bits(self, discriminant: usize, padding: &EnumPaddingSimValue) { + let (None, _variant_bits) = self.known_variant(discriminant, padding) else { + panic!("expected variant to have no field"); + }; + } + #[track_caller] + pub fn variant_with_field_to_bits( + self, + discriminant: usize, + value: &SimValue, + padding: &EnumPaddingSimValue, + ) { + let (Some(variant_ty), variant_bits) = self.known_variant(discriminant, padding) else { + panic!("expected variant to have a field"); + }; + assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); + variant_bits.copy_from_bitslice(SimValue::bits(value).bits()); + } } #[hdl] @@ -417,6 +719,25 @@ impl, Rhs: Type> ExprPartialEq> fo } } +impl, Rhs: Type> SimValuePartialEq> for HdlOption { + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + type SimValueMatch = ::SimValue; + match (&**this, &**other) { + (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlNone(_)) => { + true + } + (SimValueMatch::::HdlSome(..), SimValueMatch::>::HdlNone(_)) + | (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlSome(..)) => { + false + } + ( + SimValueMatch::::HdlSome(l, _), + SimValueMatch::>::HdlSome(r, _), + ) => l == r, + } + } +} + #[allow(non_snake_case)] pub fn HdlNone() -> Expr> { HdlOption[T::TYPE].HdlNone() diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 016ec8e..f511c97 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -700,6 +700,7 @@ impl CastToBits for T { } pub trait CastBitsTo { + #[track_caller] fn cast_bits_to(&self, ty: T) -> Expr; } diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index 236f240..a956dd5 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -7,6 +7,7 @@ use crate::{ Expr, NotALiteralExpr, ToExpr, ToLiteralBits, }, intern::{Intern, Interned, Memoize}, + sim::value::SimValue, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, @@ -49,6 +50,15 @@ pub trait KnownSize: + IntoIterator> + TryFrom>> + Into>>; + type ArraySimValue: AsRef<[SimValue]> + + AsMut<[SimValue]> + + BorrowMut<[SimValue]> + + 'static + + Clone + + std::fmt::Debug + + IntoIterator> + + TryFrom>> + + Into>>; } macro_rules! known_widths { @@ -60,6 +70,7 @@ macro_rules! known_widths { }> { const SIZE: Self = Self; type ArrayMatch = [Expr; Self::VALUE]; + type ArraySimValue = [SimValue; Self::VALUE]; } }; ([2 $($rest:tt)*] $($bits:literal)+) => { @@ -72,6 +83,7 @@ macro_rules! known_widths { impl KnownSize for ConstUsize<{2 $(* $rest)*}> { const SIZE: Self = Self; type ArrayMatch = [Expr; Self::VALUE]; + type ArraySimValue = [SimValue; Self::VALUE]; } }; } @@ -100,6 +112,15 @@ pub trait Size: + IntoIterator> + TryFrom>> + Into>>; + type ArraySimValue: AsRef<[SimValue]> + + AsMut<[SimValue]> + + BorrowMut<[SimValue]> + + 'static + + Clone + + std::fmt::Debug + + IntoIterator> + + TryFrom>> + + Into>>; const KNOWN_VALUE: Option; type SizeType: SizeType + Copy @@ -125,6 +146,7 @@ impl SizeType for usize { impl Size for DynSize { type ArrayMatch = Box<[Expr]>; + type ArraySimValue = Box<[SimValue]>; const KNOWN_VALUE: Option = None; type SizeType = usize; @@ -147,6 +169,7 @@ impl SizeType for T { impl Size for T { type ArrayMatch = ::ArrayMatch; + type ArraySimValue = ::ArraySimValue; const KNOWN_VALUE: Option = Some(T::VALUE); @@ -287,6 +310,7 @@ macro_rules! impl_int { impl Type for $name { type BaseType = $pretty_name; type MaskType = Bool; + type SimValue = $value; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -306,6 +330,20 @@ macro_rules! impl_int { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), self.width()); + $value::new(Arc::new(bits.to_bitvec())) + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), self.width()); + assert_eq!(value.width(), self.width()); + value.bits_mut().copy_from_bitslice(bits); + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), self.width()); + assert_eq!(value.width(), self.width()); + bits.copy_from_bitslice(value.bits()); + } } impl StaticType for $name { @@ -331,7 +369,7 @@ macro_rules! impl_int { } } - #[derive(Clone, PartialEq, Eq, Hash)] + #[derive(Clone, Eq, Hash)] pub struct $value { bits: Arc, _phantom: PhantomData, @@ -351,9 +389,15 @@ macro_rules! impl_int { } } - impl PartialOrd for $value { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) + impl PartialEq<$value> for $value { + fn eq(&self, other: &$value) -> bool { + self.to_bigint() == other.to_bigint() + } + } + + impl PartialOrd<$value> for $value { + fn partial_cmp(&self, other: &$value) -> Option { + Some(self.to_bigint().cmp(&other.to_bigint())) } } @@ -401,6 +445,9 @@ macro_rules! impl_int { pub fn bits(&self) -> &Arc { &self.bits } + pub fn bits_mut(&mut self) -> &mut BitSlice { + Arc::::make_mut(&mut self.bits) + } } impl ToLiteralBits for $value { @@ -748,6 +795,7 @@ impl Bool { impl Type for Bool { type BaseType = Bool; type MaskType = Bool; + type SimValue = bool; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -765,6 +813,18 @@ impl Type for Bool { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), 1); + bits[0] + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), 1); + *value = bits[0]; + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), 1); + bits.set(0, *value); + } } impl StaticType for Bool { diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index 512572d..0843589 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -8,6 +8,8 @@ extern crate self as fayalite; +#[doc(hidden)] +pub use bitvec as __bitvec; #[doc(hidden)] pub use std as __std; diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index dd6cff6..27bb04e 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +use bitvec::slice::BitSlice; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ @@ -10,6 +11,7 @@ use crate::{ }, int::Bool, intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize}, + sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; @@ -246,6 +248,7 @@ impl PhantomConst { impl Type for PhantomConst { type BaseType = PhantomConst; type MaskType = (); + type SimValue = (); impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { @@ -266,6 +269,19 @@ impl Type for PhantomConst { fn source_location() -> SourceLocation { SourceLocation::builtin() } + + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert!(bits.is_empty()); + () + } + + fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { + assert!(bits.is_empty()); + } + + fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { + assert!(bits.is_empty()); + } } impl StaticType for PhantomConst @@ -311,3 +327,10 @@ impl ExprPartialOrd for PhantomConst { true.to_expr() } } + +impl SimValuePartialEq for PhantomConst { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + assert_eq!(SimValue::ty(this), SimValue::ty(other)); + true + } +} diff --git a/crates/fayalite/src/reset.rs b/crates/fayalite/src/reset.rs index 9328365..312a8ea 100644 --- a/crates/fayalite/src/reset.rs +++ b/crates/fayalite/src/reset.rs @@ -7,6 +7,7 @@ use crate::{ source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; +use bitvec::slice::BitSlice; mod sealed { pub trait ResetTypeSealed {} @@ -45,6 +46,7 @@ macro_rules! reset_type { impl Type for $name { type BaseType = $name; type MaskType = Bool; + type SimValue = bool; impl_match_variant_as_self!(); @@ -66,6 +68,21 @@ macro_rules! reset_type { }; retval } + + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), 1); + bits[0] + } + + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), 1); + *value = bits[0]; + } + + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), 1); + bits.set(0, *value); + } } impl $name { diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index b508756..9be4889 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -14,7 +14,7 @@ use crate::{ }, ExprEnum, Flow, ToLiteralBits, }, - int::{BoolOrIntType, IntType, SIntValue, UIntValue}, + int::{BoolOrIntType, UIntValue}, intern::{ Intern, Interned, InternedCompare, Memoize, PtrEqWithTypeId, SupportsPtrEqWithTypeId, }, @@ -38,6 +38,7 @@ use crate::{ TypeIndexRange, TypeLayout, TypeLen, TypeParts, }, time::{SimDuration, SimInstant}, + value::SimValue, }, ty::StaticType, util::{BitSliceWriteWithBase, DebugAsDisplay}, @@ -72,6 +73,7 @@ use std::{ mod interpreter; pub mod time; +pub mod value; pub mod vcd; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] @@ -5904,635 +5906,6 @@ impl SimTraceKind { } } -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct SimValue { - ty: T, - bits: BitVec, -} - -impl fmt::Debug for SimValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SimValue") - .field("ty", &self.ty) - .field("bits", &BitSliceWriteWithBase(&self.bits)) - .finish() - } -} - -impl SimValue { - #[track_caller] - fn to_expr_impl(ty: CanonicalType, bits: &BitSlice) -> Expr { - match ty { - CanonicalType::UInt(_) => Expr::canonical(::bits_to_expr(Cow::Borrowed(bits))), - CanonicalType::SInt(_) => Expr::canonical(::bits_to_expr(Cow::Borrowed(bits))), - CanonicalType::Bool(_) => Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits))), - CanonicalType::Array(ty) => { - let element_bit_width = ty.element().bit_width(); - Expr::::canonical( - crate::expr::ops::ArrayLiteral::new( - ty.element(), - (0..ty.len()) - .map(|array_index| { - let start = element_bit_width * array_index; - let end = start + element_bit_width; - Self::to_expr_impl(ty.element(), &bits[start..end]) - }) - .collect(), - ) - .to_expr(), - ) - } - CanonicalType::Enum(ty) => { - let discriminant_bit_width = ty.discriminant_bit_width(); - let mut variant_index = [0; mem::size_of::()]; - variant_index.view_bits_mut::()[0..discriminant_bit_width] - .clone_from_bitslice(&bits[..discriminant_bit_width]); - let variant_index = usize::from_le_bytes(variant_index); - if let Some(variant) = ty.variants().get(variant_index) { - let data_bit_width = variant.ty.map_or(0, CanonicalType::bit_width); - Expr::canonical( - crate::expr::ops::EnumLiteral::new_by_index( - ty, - variant_index, - variant.ty.map(|ty| { - Self::to_expr_impl( - ty, - &bits[discriminant_bit_width - ..discriminant_bit_width + data_bit_width], - ) - }), - ) - .to_expr(), - ) - } else { - Expr::canonical(::bits_to_expr(Cow::Borrowed(bits)).cast_bits_to(ty)) - } - } - CanonicalType::Bundle(ty) => Expr::canonical( - crate::expr::ops::BundleLiteral::new( - ty, - ty.fields() - .iter() - .zip(ty.field_offsets().iter()) - .map(|(field, &field_offset)| { - Self::to_expr_impl( - field.ty, - &bits[field_offset..field_offset + field.ty.bit_width()], - ) - }) - .collect(), - ) - .to_expr(), - ), - CanonicalType::AsyncReset(ty) => { - Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) - } - CanonicalType::SyncReset(ty) => { - Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) - } - CanonicalType::Reset(_) => panic!( - "can't convert SimValue to Expr -- \ - can't deduce whether reset value should be sync or async" - ), - CanonicalType::Clock(ty) => { - Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) - } - CanonicalType::PhantomConst(ty) => Expr::canonical(ty.to_expr()), - } - } -} - -impl ToExpr for SimValue { - type Type = T; - - #[track_caller] - fn to_expr(&self) -> Expr { - Expr::from_canonical(SimValue::to_expr_impl(self.ty.canonical(), &self.bits)) - } -} - -impl ToSimValue for SimValue { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - assert_eq!(self.ty, ty); - self.clone() - } - - #[track_caller] - fn into_sim_value(self, ty: T) -> SimValue { - assert_eq!(self.ty, ty); - self - } - - #[track_caller] - fn box_into_sim_value(self: Box, ty: T) -> SimValue { - assert_eq!(self.ty, ty); - *self - } -} - -impl ToSimValue for BitVec { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - self.clone().into_sim_value(ty) - } - - #[track_caller] - fn into_sim_value(self, ty: T) -> SimValue { - assert_eq!(ty.canonical().bit_width(), self.len()); - SimValue { ty, bits: self } - } - - #[track_caller] - fn box_into_sim_value(self: Box, ty: T) -> SimValue { - Self::into_sim_value(*self, ty) - } -} - -impl ToSimValue for bitvec::boxed::BitBox { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - self.clone().into_sim_value(ty) - } - - #[track_caller] - fn into_sim_value(self, ty: T) -> SimValue { - assert_eq!(ty.canonical().bit_width(), self.len()); - SimValue { - ty, - bits: self.into_bitvec(), - } - } - - #[track_caller] - fn box_into_sim_value(self: Box, ty: T) -> SimValue { - Self::into_sim_value(*self, ty) - } -} - -impl ToSimValue for BitSlice { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - assert_eq!(ty.canonical().bit_width(), self.len()); - SimValue { - ty, - bits: self.to_bitvec(), - } - } -} - -impl SimValue { - pub fn ty(&self) -> T { - self.ty - } - pub fn bits(&self) -> &BitSlice { - &self.bits - } - pub fn into_bits(self) -> BitVec { - self.bits - } - #[track_caller] - pub fn from_canonical(v: SimValue) -> Self { - Self { - ty: T::from_canonical(v.ty), - bits: v.bits, - } - } - pub fn into_canonical(self) -> SimValue { - SimValue { - ty: self.ty.canonical(), - bits: self.bits, - } - } - #[track_caller] - pub fn from_dyn_int(v: SimValue) -> Self - where - T: IntType, - { - Self { - ty: T::from_dyn_int(v.ty), - bits: v.bits, - } - } - pub fn into_dyn_int(self) -> SimValue - where - T: IntType, - { - SimValue { - ty: self.ty.as_dyn_int(), - bits: self.bits, - } - } - #[track_caller] - pub fn from_bundle(v: SimValue) -> Self - where - T: BundleType, - { - Self { - ty: T::from_canonical(CanonicalType::Bundle(v.ty)), - bits: v.bits, - } - } - pub fn into_bundle(self) -> SimValue - where - T: BundleType, - { - SimValue { - ty: Bundle::from_canonical(self.ty.canonical()), - bits: self.bits, - } - } - #[track_caller] - pub fn from_enum(v: SimValue) -> Self - where - T: EnumType, - { - Self { - ty: T::from_canonical(CanonicalType::Enum(v.ty)), - bits: v.bits, - } - } - pub fn into_enum(self) -> SimValue - where - T: EnumType, - { - SimValue { - ty: Enum::from_canonical(self.ty.canonical()), - bits: self.bits, - } - } -} - -pub trait ToSimValue { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue; - #[track_caller] - fn into_sim_value(self, ty: T) -> SimValue - where - Self: Sized, - { - self.to_sim_value(ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: T) -> SimValue { - self.to_sim_value(ty) - } -} - -impl, T: Type> ToSimValue for &'_ This { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - This::to_sim_value(self, ty) - } -} - -impl, T: Type> ToSimValue for &'_ mut This { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - This::to_sim_value(self, ty) - } -} - -impl, T: Type> ToSimValue for Box { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - This::to_sim_value(self, ty) - } - #[track_caller] - fn into_sim_value(self, ty: T) -> SimValue { - This::box_into_sim_value(self, ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: T) -> SimValue { - This::box_into_sim_value(*self, ty) - } -} - -impl + Send + Sync + 'static, T: Type> ToSimValue - for Interned -{ - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - This::to_sim_value(self, ty) - } -} - -impl SimValue> { - #[track_caller] - pub fn from_array_elements< - I: IntoIterator, IntoIter: ExactSizeIterator>, - >( - elements: I, - ty: ArrayType, - ) -> Self { - let mut iter = elements.into_iter(); - assert_eq!(iter.len(), ty.len()); - let Some(first) = iter.next() else { - return SimValue { - ty, - bits: BitVec::new(), - }; - }; - let SimValue { - ty: element_ty, - mut bits, - } = first.into_sim_value(ty.element()); - assert_eq!(element_ty, ty.element()); - bits.reserve(ty.type_properties().bit_width - bits.len()); - for element in iter { - let SimValue { - ty: element_ty, - bits: element_bits, - } = element.into_sim_value(ty.element()); - assert_eq!(element_ty, ty.element()); - bits.extend_from_bitslice(&element_bits); - } - SimValue { ty, bits } - } -} - -impl, T: Type> ToSimValue> for [Element] { - #[track_caller] - fn to_sim_value(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } -} - -impl> ToSimValue for [Element] { - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } -} - -impl, T: Type, const N: usize> ToSimValue> for [Element; N] -where - ConstUsize: KnownSize, -{ - #[track_caller] - fn to_sim_value(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn into_sim_value(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { - SimValue::from_array_elements( as From>>::from(self), ty) - } -} - -impl, T: Type, const N: usize> ToSimValue> for [Element; N] -where - ConstUsize: KnownSize, -{ - #[track_caller] - fn to_sim_value(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn into_sim_value(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { - SimValue::from_array_elements( as From>>::from(self), ty) - } -} - -impl, const N: usize> ToSimValue - for [Element; N] -{ - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn into_sim_value(self, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements( - as From>>::from(self), - ::from_canonical(ty), - ) - .into_canonical() - } -} - -impl, T: Type> ToSimValue> for Vec { - #[track_caller] - fn to_sim_value(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn into_sim_value(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(self, ty) - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { - SimValue::from_array_elements(*self, ty) - } -} - -impl> ToSimValue for Vec { - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn into_sim_value(self, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() - } - #[track_caller] - fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { - SimValue::from_array_elements(*self, ::from_canonical(ty)).into_canonical() - } -} - -impl ToSimValue for Expr { - #[track_caller] - fn to_sim_value(&self, ty: T) -> SimValue { - assert_eq!(Expr::ty(*self), ty); - SimValue { - ty, - bits: self - .to_literal_bits() - .expect("must be a literal expression") - .to_bitvec(), - } - } -} - -macro_rules! impl_to_sim_value_for_bool_like { - ($ty:ident) => { - impl ToSimValue<$ty> for bool { - fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> { - SimValue { - ty, - bits: BitVec::repeat(*self, 1), - } - } - } - }; -} - -impl_to_sim_value_for_bool_like!(Bool); -impl_to_sim_value_for_bool_like!(AsyncReset); -impl_to_sim_value_for_bool_like!(SyncReset); -impl_to_sim_value_for_bool_like!(Reset); -impl_to_sim_value_for_bool_like!(Clock); - -impl ToSimValue for bool { - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - match ty { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Array(_) - | CanonicalType::Enum(_) - | CanonicalType::Bundle(_) - | CanonicalType::PhantomConst(_) => { - panic!("can't create SimValue from bool: expected value of type: {ty:?}"); - } - CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => SimValue { - ty, - bits: BitVec::repeat(*self, 1), - }, - } - } -} - -macro_rules! impl_to_sim_value_for_primitive_int { - ($prim:ident) => { - impl ToSimValue<<$prim as ToExpr>::Type> for $prim { - #[track_caller] - fn to_sim_value( - &self, - ty: <$prim as ToExpr>::Type, - ) -> SimValue<<$prim as ToExpr>::Type> { - SimValue { - ty, - bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping( - &self.to_le_bytes(), - ty.width(), - ), - } - } - } - - impl ToSimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { - #[track_caller] - fn to_sim_value( - &self, - ty: <<$prim as ToExpr>::Type as IntType>::Dyn, - ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { - SimValue { - ty, - bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping( - &self.to_le_bytes(), - ty.width(), - ), - } - } - } - - impl ToSimValue for $prim { - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); - self.to_sim_value(ty).into_canonical() - } - } - }; -} - -impl_to_sim_value_for_primitive_int!(u8); -impl_to_sim_value_for_primitive_int!(u16); -impl_to_sim_value_for_primitive_int!(u32); -impl_to_sim_value_for_primitive_int!(u64); -impl_to_sim_value_for_primitive_int!(u128); -impl_to_sim_value_for_primitive_int!(usize); -impl_to_sim_value_for_primitive_int!(i8); -impl_to_sim_value_for_primitive_int!(i16); -impl_to_sim_value_for_primitive_int!(i32); -impl_to_sim_value_for_primitive_int!(i64); -impl_to_sim_value_for_primitive_int!(i128); -impl_to_sim_value_for_primitive_int!(isize); - -macro_rules! impl_to_sim_value_for_int_value { - ($IntValue:ident, $Int:ident, $IntType:ident) => { - impl ToSimValue<$IntType> for $IntValue { - fn to_sim_value(&self, ty: $IntType) -> SimValue<$IntType> { - self.bits().to_bitvec().into_sim_value(ty) - } - - fn into_sim_value(self, ty: $IntType) -> SimValue<$IntType> { - Arc::try_unwrap(self.into_bits()) - .unwrap_or_else(|v: Arc| v.to_bitvec()) - .into_sim_value(ty) - } - - fn box_into_sim_value( - self: Box, - ty: $IntType, - ) -> SimValue<$IntType> { - Self::into_sim_value(*self, ty) - } - } - - impl ToSimValue<$Int> for $IntValue { - fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> { - self.bits().to_bitvec().into_sim_value(ty) - } - - fn into_sim_value(self, ty: $Int) -> SimValue<$Int> { - Arc::try_unwrap(self.into_bits()) - .unwrap_or_else(|v: Arc| v.to_bitvec()) - .into_sim_value(ty) - } - - fn box_into_sim_value(self: Box, ty: $Int) -> SimValue<$Int> { - Self::into_sim_value(*self, ty) - } - } - - impl ToSimValue for $IntValue { - #[track_caller] - fn to_sim_value(&self, ty: CanonicalType) -> SimValue { - ToSimValue::<$Int>::to_sim_value(self, $Int::from_canonical(ty)).into_canonical() - } - - #[track_caller] - fn into_sim_value(self, ty: CanonicalType) -> SimValue { - ToSimValue::<$Int>::into_sim_value(self, $Int::from_canonical(ty)).into_canonical() - } - - #[track_caller] - fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { - Self::into_sim_value(*self, ty) - } - } - }; -} - -impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); -impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] enum MaybeNeedsSettle { NeedsSettle(S), @@ -7024,19 +6397,19 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo struct ReadFn { compiled_value: CompiledValue, io: Expr, - bits: BitVec, } impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn { type Output = SimValue; fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { - compiled_value, + let Self { compiled_value, io } = self; + SimulationImpl::read_no_settle_helper( + state, io, - bits, - } = self; - SimulationImpl::read_no_settle_helper(state, io, compiled_value, bits) + compiled_value, + UIntValue::new(Arc::new(BitVec::repeat(false, Expr::ty(io).bit_width()))), + ) } } @@ -7390,7 +6763,7 @@ impl SimulationImpl { (WaitTarget::Instant(instant), None) => Some(instant), (WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)), (WaitTarget::Change { key, value }, retval) => { - if Self::value_changed(&mut self.state, key, &value.bits) { + if Self::value_changed(&mut self.state, key, SimValue::bits(value).bits()) { Some(self.instant) } else { retval @@ -7688,7 +7061,7 @@ impl SimulationImpl { } } #[track_caller] - fn read_write_sim_value_helper( + fn read_write_sim_value_helper( state: &mut interpreter::State, compiled_value: CompiledValue, start_bit_index: usize, @@ -7783,15 +7156,13 @@ impl SimulationImpl { state: &mut interpreter::State, io: Expr, compiled_value: CompiledValue, - mut bits: BitVec, + mut bits: UIntValue, ) -> SimValue { - bits.clear(); - bits.resize(compiled_value.layout.ty.bit_width(), false); SimulationImpl::read_write_sim_value_helper( state, compiled_value, 0, - &mut bits, + bits.bits_mut(), |_signed, bit_range, bits, value| { ::copy_bits_from_bigint_wrapping(value, &mut bits[bit_range]); }, @@ -7802,10 +7173,7 @@ impl SimulationImpl { bits[bit_range].clone_from_bitslice(bitslice); }, ); - SimValue { - ty: Expr::ty(io), - bits, - } + SimValue::from_bits(Expr::ty(io), bits) } /// doesn't modify `bits` fn value_changed( @@ -7847,11 +7215,7 @@ impl SimulationImpl { ) { let compiled_value = self.get_module(which_module).read_helper(io, which_module); let value = compiled_value - .map(|compiled_value| ReadFn { - compiled_value, - io, - bits: BitVec::new(), - }) + .map(|compiled_value| ReadFn { compiled_value, io }) .apply_no_settle(&mut self.state); let (MaybeNeedsSettle::NeedsSettle(compiled_value) | MaybeNeedsSettle::NoSettleNeeded(compiled_value)) = compiled_value; @@ -7868,12 +7232,12 @@ impl SimulationImpl { .get_module_mut(which_module) .write_helper(io, which_module); self.state_ready_to_run = true; - assert_eq!(Expr::ty(io), value.ty()); + assert_eq!(Expr::ty(io), SimValue::ty(value)); Self::read_write_sim_value_helper( &mut self.state, compiled_value, 0, - &mut value.bits(), + &mut value.bits().bits(), |signed, bit_range, bits, value| { if signed { *value = SInt::bits_to_bigint(&bits[bit_range]); @@ -8167,10 +7531,10 @@ macro_rules! impl_simulation_methods { SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) } $(#[$track_caller])? - pub $($async)? fn write>(&mut $self, io: Expr, value: V) { + pub $($async)? fn write>(&mut $self, io: Expr, value: V) { $self.sim_impl.borrow_mut().write( Expr::canonical(io), - &value.into_sim_value(Expr::ty(io)).into_canonical(), + &SimValue::into_canonical(value.into_sim_value(Expr::ty(io))), $which_module, ); } diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs new file mode 100644 index 0000000..3e45016 --- /dev/null +++ b/crates/fayalite/src/sim/value.rs @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{ + array::{Array, ArrayType}, + bundle::{Bundle, BundleType}, + clock::Clock, + enum_::{Enum, EnumType}, + expr::{CastBitsTo, Expr, ToExpr}, + int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, + reset::{AsyncReset, Reset, SyncReset}, + ty::{CanonicalType, Type}, + util::{ + alternating_cell::{AlternatingCell, AlternatingCellMethods}, + ConstUsize, + }, +}; +use bitvec::{slice::BitSlice, vec::BitVec}; +use std::{ + fmt, + ops::{Deref, DerefMut}, + sync::Arc, +}; + +#[derive(Copy, Clone, Eq, PartialEq)] +enum ValidFlags { + BothValid = 0, + OnlyValueValid = 1, + OnlyBitsValid = 2, +} + +#[derive(Clone)] +struct SimValueInner { + value: T::SimValue, + bits: UIntValue, + valid_flags: ValidFlags, + ty: T, +} + +impl SimValueInner { + fn fill_bits(&mut self) { + match self.valid_flags { + ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {} + ValidFlags::OnlyValueValid => { + self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()); + self.valid_flags = ValidFlags::BothValid; + } + } + } + fn into_bits(mut self) -> UIntValue { + self.fill_bits(); + self.bits + } + fn bits_mut(&mut self) -> &mut UIntValue { + self.fill_bits(); + self.valid_flags = ValidFlags::OnlyBitsValid; + &mut self.bits + } + fn fill_value(&mut self) { + match self.valid_flags { + ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} + ValidFlags::OnlyBitsValid => { + self.ty + .sim_value_clone_from_bits(&mut self.value, self.bits.bits()); + self.valid_flags = ValidFlags::BothValid; + } + } + } + fn into_value(mut self) -> T::SimValue { + self.fill_value(); + self.value + } + fn value_mut(&mut self) -> &mut T::SimValue { + self.fill_value(); + self.valid_flags = ValidFlags::OnlyValueValid; + &mut self.value + } +} + +impl AlternatingCellMethods for SimValueInner { + fn unique_to_shared(&mut self) { + match self.valid_flags { + ValidFlags::BothValid => return, + ValidFlags::OnlyValueValid => { + self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()) + } + ValidFlags::OnlyBitsValid => self + .ty + .sim_value_clone_from_bits(&mut self.value, self.bits.bits()), + } + self.valid_flags = ValidFlags::BothValid; + } + + fn shared_to_unique(&mut self) {} +} + +pub struct SimValue { + inner: AlternatingCell>, +} + +impl Clone for SimValue { + fn clone(&self) -> Self { + Self { + inner: AlternatingCell::new_unique(self.inner.share().clone()), + } + } +} + +impl SimValue { + #[track_caller] + pub fn from_bits(ty: T, bits: UIntValue) -> Self { + assert_eq!(ty.canonical().bit_width(), bits.width()); + let inner = SimValueInner { + value: ty.sim_value_from_bits(bits.bits()), + bits, + valid_flags: ValidFlags::BothValid, + ty, + }; + Self { + inner: AlternatingCell::new_shared(inner), + } + } + #[track_caller] + pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { + Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec()))) + } + pub fn from_value(ty: T, value: T::SimValue) -> Self { + let inner = SimValueInner { + bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))), + value, + valid_flags: ValidFlags::OnlyValueValid, + ty, + }; + Self { + inner: AlternatingCell::new_unique(inner), + } + } + pub fn ty(this: &Self) -> T { + this.inner.share().ty + } + pub fn into_bits(this: Self) -> UIntValue { + this.inner.into_inner().into_bits() + } + pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) { + let inner = this.inner.into_inner(); + (inner.ty, inner.into_bits()) + } + pub fn bits(this: &Self) -> &UIntValue { + &this.inner.share().bits + } + pub fn bits_mut(this: &mut Self) -> &mut UIntValue { + this.inner.unique().bits_mut() + } + pub fn into_value(this: Self) -> T::SimValue { + this.inner.into_inner().into_value() + } + pub fn value(this: &Self) -> &T::SimValue { + &this.inner.share().value + } + pub fn value_mut(this: &mut Self) -> &mut T::SimValue { + this.inner.unique().value_mut() + } + #[track_caller] + pub fn from_canonical(v: SimValue) -> Self { + let (ty, bits) = SimValue::into_ty_and_bits(v); + Self::from_bits(T::from_canonical(ty), bits) + } + pub fn into_canonical(this: Self) -> SimValue { + let (ty, bits) = Self::into_ty_and_bits(this); + SimValue::from_bits(ty.canonical(), bits) + } + pub fn canonical(this: &Self) -> SimValue { + SimValue::from_bits(Self::ty(this).canonical(), Self::bits(this).clone()) + } + #[track_caller] + pub fn from_dyn_int(v: SimValue) -> Self + where + T: IntType, + { + let (ty, bits) = SimValue::into_ty_and_bits(v); + SimValue::from_bits(T::from_dyn_int(ty), bits) + } + pub fn into_dyn_int(this: Self) -> SimValue + where + T: IntType, + { + let (ty, bits) = Self::into_ty_and_bits(this); + SimValue::from_bits(ty.as_dyn_int(), bits) + } + pub fn to_dyn_int(this: &Self) -> SimValue + where + T: IntType, + { + SimValue::from_bits(Self::ty(this).as_dyn_int(), Self::bits(&this).clone()) + } + #[track_caller] + pub fn from_bundle(v: SimValue) -> Self + where + T: BundleType, + { + let (ty, bits) = SimValue::into_ty_and_bits(v); + SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits) + } + pub fn into_bundle(this: Self) -> SimValue + where + T: BundleType, + { + let (ty, bits) = Self::into_ty_and_bits(this); + SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits) + } + pub fn to_bundle(this: &Self) -> SimValue + where + T: BundleType, + { + SimValue::from_bits( + Bundle::from_canonical(Self::ty(this).canonical()), + Self::bits(&this).clone(), + ) + } + #[track_caller] + pub fn from_enum(v: SimValue) -> Self + where + T: EnumType, + { + let (ty, bits) = SimValue::into_ty_and_bits(v); + SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits) + } + pub fn into_enum(this: Self) -> SimValue + where + T: EnumType, + { + let (ty, bits) = Self::into_ty_and_bits(this); + SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits) + } + pub fn to_enum(this: &Self) -> SimValue + where + T: EnumType, + { + SimValue::from_bits( + Enum::from_canonical(Self::ty(this).canonical()), + Self::bits(&this).clone(), + ) + } +} + +impl Deref for SimValue { + type Target = T::SimValue; + + fn deref(&self) -> &Self::Target { + Self::value(self) + } +} + +impl DerefMut for SimValue { + fn deref_mut(&mut self) -> &mut Self::Target { + Self::value_mut(self) + } +} + +impl fmt::Debug for SimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let inner = self.inner.share(); + f.debug_struct("SimValue") + .field("ty", &inner.ty) + .field("value", &inner.value) + .finish() + } +} + +impl ToExpr for SimValue { + type Type = T; + + #[track_caller] + fn to_expr(&self) -> Expr { + let inner = self.inner.share(); + inner.bits.cast_bits_to(inner.ty) + } +} + +pub trait SimValuePartialEq: Type { + #[track_caller] + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool; +} + +impl, U: Type> PartialEq> for SimValue { + #[track_caller] + fn eq(&self, other: &SimValue) -> bool { + T::sim_value_eq(self, other) + } +} + +impl SimValuePartialEq> for UIntType { + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + **this == **other + } +} + +impl SimValuePartialEq> for SIntType { + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + **this == **other + } +} + +impl SimValuePartialEq for Bool { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } +} + +pub trait ToSimValue { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue; + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue + where + Self: Sized, + { + self.to_sim_value(ty) + } + #[track_caller] + fn arc_into_sim_value(self: Arc, ty: T) -> SimValue { + self.to_sim_value(ty) + } + #[track_caller] + fn arc_to_sim_value(self: &Arc, ty: T) -> SimValue { + self.to_sim_value(ty) + } +} + +impl ToSimValue for SimValue { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + assert_eq!(SimValue::ty(self), ty); + self.clone() + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + assert_eq!(SimValue::ty(&self), ty); + self + } +} + +impl ToSimValue for BitVec { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + self.clone().into_sim_value(ty) + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + Arc::new(self).arc_into_sim_value(ty) + } + + #[track_caller] + fn arc_into_sim_value(self: Arc, ty: T) -> SimValue { + SimValue::from_bits(ty, UIntValue::new_dyn(self)) + } + + #[track_caller] + fn arc_to_sim_value(self: &Arc, ty: T) -> SimValue { + SimValue::from_bits(ty, UIntValue::new_dyn(self.clone())) + } +} + +impl ToSimValue for bitvec::boxed::BitBox { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + self.clone().into_sim_value(ty) + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + self.into_bitvec().into_sim_value(ty) + } +} + +impl ToSimValue for BitSlice { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + self.to_bitvec().into_sim_value(ty) + } +} + +impl, T: Type> ToSimValue for &'_ This { + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl, T: Type> ToSimValue for &'_ mut This { + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl, T: Type> ToSimValue for Arc { + fn to_sim_value(&self, ty: T) -> SimValue { + This::arc_to_sim_value(self, ty) + } + fn into_sim_value(self, ty: T) -> SimValue { + This::arc_into_sim_value(self, ty) + } +} + +impl + Send + Sync + 'static, T: Type> ToSimValue + for crate::intern::Interned +{ + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl, T: Type> ToSimValue for Box { + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } + fn into_sim_value(self, ty: T) -> SimValue { + This::into_sim_value(*self, ty) + } +} + +impl SimValue> { + #[track_caller] + pub fn from_array_elements>>( + ty: ArrayType, + elements: I, + ) -> Self { + let element_ty = ty.element(); + let elements = Vec::from_iter( + elements + .into_iter() + .map(|element| element.into_sim_value(element_ty)), + ); + assert_eq!(elements.len(), ty.len()); + SimValue::from_value(ty, elements.try_into().ok().expect("already checked len")) + } +} + +impl, T: Type> ToSimValue> for [Element] { + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } +} + +impl> ToSimValue for [Element] { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(SimValue::from_array_elements( + ::from_canonical(ty), + self, + )) + } +} + +impl, T: Type, const N: usize> ToSimValue> for [Element; N] +where + ConstUsize: KnownSize, +{ + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } +} + +impl, T: Type, const N: usize> ToSimValue> for [Element; N] { + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } +} + +impl, const N: usize> ToSimValue + for [Element; N] +{ + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(SimValue::from_array_elements( + ::from_canonical(ty), + self, + )) + } + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(SimValue::from_array_elements( + ::from_canonical(ty), + self, + )) + } +} + +impl, T: Type> ToSimValue> for Vec { + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(ty, self) + } +} + +impl> ToSimValue for Vec { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(SimValue::from_array_elements( + ::from_canonical(ty), + self, + )) + } + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(SimValue::from_array_elements( + ::from_canonical(ty), + self, + )) + } +} + +impl ToSimValue for Expr { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + assert_eq!(Expr::ty(*self), ty); + SimValue::from_bitslice( + ty, + &crate::expr::ToLiteralBits::to_literal_bits(self) + .expect("must be a literal expression"), + ) + } +} + +macro_rules! impl_to_sim_value_for_bool_like { + ($ty:ident) => { + impl ToSimValue<$ty> for bool { + fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> { + SimValue::from_value(ty, *self) + } + } + }; +} + +impl_to_sim_value_for_bool_like!(Bool); +impl_to_sim_value_for_bool_like!(AsyncReset); +impl_to_sim_value_for_bool_like!(SyncReset); +impl_to_sim_value_for_bool_like!(Reset); +impl_to_sim_value_for_bool_like!(Clock); + +impl ToSimValue for bool { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + match ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::PhantomConst(_) => { + panic!("can't create SimValue from bool: expected value of type: {ty:?}"); + } + CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => { + SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))) + } + } + } +} + +macro_rules! impl_to_sim_value_for_primitive_int { + ($prim:ident) => { + impl ToSimValue<<$prim as ToExpr>::Type> for $prim { + #[track_caller] + fn to_sim_value( + &self, + ty: <$prim as ToExpr>::Type, + ) -> SimValue<<$prim as ToExpr>::Type> { + SimValue::from_value(ty, (*self).into()) + } + } + + impl ToSimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { + #[track_caller] + fn to_sim_value( + &self, + ty: <<$prim as ToExpr>::Type as IntType>::Dyn, + ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { + SimValue::from_value( + ty, + <<$prim as ToExpr>::Type as Type>::SimValue::from(*self).as_dyn_int(), + ) + } + } + + impl ToSimValue for $prim { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); + SimValue::into_canonical(self.to_sim_value(ty)) + } + } + }; +} + +impl_to_sim_value_for_primitive_int!(u8); +impl_to_sim_value_for_primitive_int!(u16); +impl_to_sim_value_for_primitive_int!(u32); +impl_to_sim_value_for_primitive_int!(u64); +impl_to_sim_value_for_primitive_int!(u128); +impl_to_sim_value_for_primitive_int!(usize); +impl_to_sim_value_for_primitive_int!(i8); +impl_to_sim_value_for_primitive_int!(i16); +impl_to_sim_value_for_primitive_int!(i32); +impl_to_sim_value_for_primitive_int!(i64); +impl_to_sim_value_for_primitive_int!(i128); +impl_to_sim_value_for_primitive_int!(isize); + +macro_rules! impl_to_sim_value_for_int_value { + ($IntValue:ident, $Int:ident, $IntType:ident) => { + impl ToSimValue<$IntType> for $IntValue { + fn to_sim_value(&self, ty: $IntType) -> SimValue<$IntType> { + self.bits().to_sim_value(ty) + } + + fn into_sim_value(self, ty: $IntType) -> SimValue<$IntType> { + self.into_bits().into_sim_value(ty) + } + } + + impl ToSimValue<$Int> for $IntValue { + fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> { + self.bits().to_sim_value(ty) + } + + fn into_sim_value(self, ty: $Int) -> SimValue<$Int> { + self.into_bits().into_sim_value(ty) + } + } + + impl ToSimValue for $IntValue { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(self.to_sim_value($Int::from_canonical(ty))) + } + + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + SimValue::into_canonical(self.into_sim_value($Int::from_canonical(ty))) + } + } + }; +} + +impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); +impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index 2786782..cd26c9b 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -7,14 +7,15 @@ use crate::{ clock::Clock, enum_::Enum, expr::Expr, - int::{Bool, SInt, UInt}, + int::{Bool, SInt, UInt, UIntValue}, intern::{Intern, Interned}, phantom_const::PhantomConst, reset::{AsyncReset, Reset, SyncReset}, source_location::SourceLocation, util::ConstUsize, }; -use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index}; +use bitvec::slice::BitSlice; +use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index, sync::Arc}; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] #[non_exhaustive] @@ -268,6 +269,7 @@ pub trait Type: { type BaseType: BaseType; type MaskType: Type; + type SimValue: fmt::Debug + Clone + 'static; type MatchVariant: 'static + Send + Sync; type MatchActiveScope; type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< @@ -285,6 +287,9 @@ pub trait Type: fn canonical(&self) -> CanonicalType; fn from_canonical(canonical_type: CanonicalType) -> Self; fn source_location() -> SourceLocation; + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue; + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice); + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice); } pub trait BaseType: Type + sealed::BaseTypeSealed + Into {} @@ -314,6 +319,7 @@ pub trait TypeWithDeref: Type { impl Type for CanonicalType { type BaseType = CanonicalType; type MaskType = CanonicalType; + type SimValue = OpaqueSimValue; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { match self { @@ -339,6 +345,48 @@ impl Type for CanonicalType { fn source_location() -> SourceLocation { SourceLocation::builtin() } + fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { + assert_eq!(bits.len(), self.bit_width()); + OpaqueSimValue::from_bitslice(bits) + } + fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { + assert_eq!(bits.len(), self.bit_width()); + assert_eq!(value.bit_width(), self.bit_width()); + value.bits_mut().bits_mut().copy_from_bitslice(bits); + } + fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { + assert_eq!(bits.len(), self.bit_width()); + assert_eq!(value.bit_width(), self.bit_width()); + bits.copy_from_bitslice(value.bits().bits()); + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct OpaqueSimValue { + bits: UIntValue, +} + +impl OpaqueSimValue { + pub fn bit_width(&self) -> usize { + self.bits.width() + } + pub fn bits(&self) -> &UIntValue { + &self.bits + } + pub fn bits_mut(&mut self) -> &mut UIntValue { + &mut self.bits + } + pub fn into_bits(self) -> UIntValue { + self.bits + } + pub fn from_bits(bits: UIntValue) -> Self { + Self { bits } + } + pub fn from_bitslice(v: &BitSlice) -> Self { + Self { + bits: UIntValue::new(Arc::new(v.to_bitvec())), + } + } } pub trait StaticType: Type { diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 66fc921..804ff19 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +pub(crate) mod alternating_cell; mod const_bool; mod const_cmp; mod const_usize; diff --git a/crates/fayalite/src/util/alternating_cell.rs b/crates/fayalite/src/util/alternating_cell.rs new file mode 100644 index 0000000..17e06a6 --- /dev/null +++ b/crates/fayalite/src/util/alternating_cell.rs @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::util::DebugAsDisplay; +use std::{ + cell::{Cell, UnsafeCell}, + fmt, +}; + +pub(crate) trait AlternatingCellMethods { + fn unique_to_shared(&mut self); + fn shared_to_unique(&mut self); +} + +#[derive(Copy, Clone, Debug)] +enum State { + Unique, + Shared, + Locked, +} + +pub(crate) struct AlternatingCell { + state: Cell, + value: UnsafeCell, +} + +impl fmt::Debug for AlternatingCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("AlternatingCell") + .field( + self.try_share() + .as_ref() + .map(|v| -> &dyn fmt::Debug { v }) + .unwrap_or(&DebugAsDisplay("<...>")), + ) + .finish() + } +} + +impl AlternatingCell { + pub(crate) const fn new_shared(value: T) -> Self + where + T: Sized, + { + Self { + state: Cell::new(State::Shared), + value: UnsafeCell::new(value), + } + } + pub(crate) const fn new_unique(value: T) -> Self + where + T: Sized, + { + Self { + state: Cell::new(State::Unique), + value: UnsafeCell::new(value), + } + } + pub(crate) fn is_unique(&self) -> bool { + matches!(self.state.get(), State::Unique) + } + pub(crate) fn is_shared(&self) -> bool { + matches!(self.state.get(), State::Shared) + } + pub(crate) fn into_inner(self) -> T + where + T: Sized, + { + self.value.into_inner() + } + pub(crate) fn try_share(&self) -> Option<&T> + where + T: AlternatingCellMethods, + { + match self.state.get() { + State::Shared => {} + State::Unique => { + struct Locked<'a>(&'a Cell); + impl Drop for Locked<'_> { + fn drop(&mut self) { + self.0.set(State::Shared); + } + } + self.state.set(State::Locked); + let lock = Locked(&self.state); + // Safety: state is Locked, so nothing else will + // access value while calling unique_to_shared. + unsafe { &mut *self.value.get() }.unique_to_shared(); + drop(lock); + } + State::Locked => return None, + } + + // Safety: state is Shared so nothing will create any mutable + // references until the returned reference's lifetime expires. + Some(unsafe { &*self.value.get() }) + } + #[track_caller] + pub(crate) fn share(&self) -> &T + where + T: AlternatingCellMethods, + { + let Some(retval) = self.try_share() else { + panic!("`share` called recursively"); + }; + retval + } + pub(crate) fn unique(&mut self) -> &mut T + where + T: AlternatingCellMethods, + { + match self.state.get() { + State::Shared => { + self.state.set(State::Unique); + self.value.get_mut().shared_to_unique(); + } + State::Unique => {} + State::Locked => unreachable!(), + } + self.value.get_mut() + } +} diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 450be54..eb5c79e 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -3,10 +3,16 @@ use fayalite::{ int::UIntValue, + memory::{ReadStruct, ReadWriteStruct, WriteStruct}, module::{instance_with_loc, reg_builder_with_loc}, prelude::*, reset::ResetType, - sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, + sim::{ + time::SimDuration, + value::{SimValue, ToSimValue}, + vcd::VcdWriterDecls, + Simulation, + }, ty::StaticType, util::RcWriter, }; @@ -396,32 +402,14 @@ fn test_enums() { sim.write_reset(sim.io().cd.rst, false); sim.advance_time(SimDuration::from_nanos(900)); type BOutTy = HdlOption<(UInt<1>, Bool)>; - #[derive(Debug)] + #[derive(Debug, PartialEq)] struct IO { en: bool, which_in: u8, data_in: u8, which_out: u8, data_out: u8, - b_out: Expr, - } - impl PartialEq for IO { - fn eq(&self, other: &Self) -> bool { - let Self { - en, - which_in, - data_in, - which_out, - data_out, - b_out, - } = *self; - en == other.en - && which_in == other.which_in - && data_in == other.data_in - && which_out == other.which_out - && data_out == other.data_out - && b_out.to_sim_value(BOutTy::TYPE) == other.b_out.to_sim_value(BOutTy::TYPE) - } + b_out: SimValue, } let io_cycles = [ IO { @@ -430,7 +418,7 @@ fn test_enums() { data_in: 0, which_out: 0, data_out: 0, - b_out: HdlNone(), + b_out: HdlNone().to_sim_value(StaticType::TYPE), }, IO { en: true, @@ -438,7 +426,7 @@ fn test_enums() { data_in: 0, which_out: 0, data_out: 0, - b_out: HdlNone(), + b_out: HdlNone().to_sim_value(StaticType::TYPE), }, IO { en: false, @@ -446,7 +434,7 @@ fn test_enums() { data_in: 0, which_out: 1, data_out: 0, - b_out: HdlSome((0_hdl_u1, false)), + b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), }, IO { en: true, @@ -454,7 +442,7 @@ fn test_enums() { data_in: 0xF, which_out: 1, data_out: 0, - b_out: HdlSome((0_hdl_u1, false)), + b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), }, IO { en: true, @@ -462,7 +450,7 @@ fn test_enums() { data_in: 0xF, which_out: 1, data_out: 0x3, - b_out: HdlSome((1_hdl_u1, true)), + b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), }, IO { en: true, @@ -470,7 +458,7 @@ fn test_enums() { data_in: 0xF, which_out: 1, data_out: 0x3, - b_out: HdlSome((1_hdl_u1, true)), + b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), }, IO { en: true, @@ -478,7 +466,7 @@ fn test_enums() { data_in: 0xF, which_out: 2, data_out: 0xF, - b_out: HdlNone(), + b_out: HdlNone().to_sim_value(StaticType::TYPE), }, ]; for ( @@ -510,7 +498,7 @@ fn test_enums() { .to_bigint() .try_into() .expect("known to be in range"), - b_out: sim.read(sim.io().b_out).to_expr(), + b_out: sim.read(sim.io().b_out), }; assert_eq!( expected, @@ -539,9 +527,9 @@ fn test_enums() { #[hdl_module(outline_generated)] pub fn memories() { #[hdl] - let r: fayalite::memory::ReadStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); + let r: ReadStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); #[hdl] - let w: fayalite::memory::WriteStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); + let w: WriteStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); #[hdl] let mut mem = memory_with_init([(0x01u8, 0x23i8); 16]); mem.read_latency(0); @@ -560,120 +548,131 @@ fn test_memories() { sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); sim.write_clock(sim.io().r.clk, false); sim.write_clock(sim.io().w.clk, false); - #[derive(Debug, PartialEq, Eq)] + #[hdl(cmp_eq)] struct IO { - r_addr: u8, - r_en: bool, - r_data: (u8, i8), - w_addr: u8, - w_en: bool, - w_data: (u8, i8), - w_mask: (bool, bool), + r_addr: UInt<4>, + r_en: Bool, + r_data: (UInt<8>, SInt<8>), + w_addr: UInt<4>, + w_en: Bool, + w_data: (UInt<8>, SInt<8>), + w_mask: (Bool, Bool), } let io_cycles = [ + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: false, - r_data: (0, 0), - w_addr: 0, + r_data: (0u8, 0i8), + w_addr: 0_hdl_u4, w_en: false, - w_data: (0, 0), + w_data: (0u8, 0i8), w_mask: (false, false), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x1, 0x23), - w_addr: 0, + r_data: (0x1u8, 0x23i8), + w_addr: 0_hdl_u4, w_en: true, - w_data: (0x10, 0x20), + w_data: (0x10u8, 0x20i8), w_mask: (true, true), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x10, 0x20), - w_addr: 0, + r_data: (0x10u8, 0x20i8), + w_addr: 0_hdl_u4, w_en: true, - w_data: (0x30, 0x40), + w_data: (0x30u8, 0x40i8), w_mask: (false, true), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x10, 0x40), - w_addr: 0, + r_data: (0x10u8, 0x40i8), + w_addr: 0_hdl_u4, w_en: true, - w_data: (0x50, 0x60), + w_data: (0x50u8, 0x60i8), w_mask: (true, false), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x50, 0x40), - w_addr: 0, + r_data: (0x50u8, 0x40i8), + w_addr: 0_hdl_u4, w_en: true, - w_data: (0x70, -0x80), + w_data: (0x70u8, -0x80i8), w_mask: (false, false), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x50, 0x40), - w_addr: 0, + r_data: (0x50u8, 0x40i8), + w_addr: 0_hdl_u4, w_en: false, - w_data: (0x90, 0xA0u8 as i8), + w_data: (0x90u8, 0xA0u8 as i8), w_mask: (false, false), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x50, 0x40), - w_addr: 1, + r_data: (0x50u8, 0x40i8), + w_addr: 1_hdl_u4, w_en: true, - w_data: (0x90, 0xA0u8 as i8), + w_data: (0x90u8, 0xA0u8 as i8), w_mask: (true, true), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x50, 0x40), - w_addr: 2, + r_data: (0x50u8, 0x40i8), + w_addr: 2_hdl_u4, w_en: true, - w_data: (0xB0, 0xC0u8 as i8), + w_data: (0xB0u8, 0xC0u8 as i8), w_mask: (true, true), }, + #[hdl] IO { - r_addr: 0, + r_addr: 0_hdl_u4, r_en: true, - r_data: (0x50, 0x40), - w_addr: 2, + r_data: (0x50u8, 0x40i8), + w_addr: 2_hdl_u4, w_en: false, - w_data: (0xD0, 0xE0u8 as i8), + w_data: (0xD0u8, 0xE0u8 as i8), w_mask: (true, true), }, + #[hdl] IO { - r_addr: 1, + r_addr: 1_hdl_u4, r_en: true, - r_data: (0x90, 0xA0u8 as i8), - w_addr: 2, + r_data: (0x90u8, 0xA0u8 as i8), + w_addr: 2_hdl_u4, w_en: false, - w_data: (0xD0, 0xE0u8 as i8), + w_data: (0xD0u8, 0xE0u8 as i8), w_mask: (true, true), }, + #[hdl] IO { - r_addr: 2, + r_addr: 2_hdl_u4, r_en: true, - r_data: (0xB0, 0xC0u8 as i8), - w_addr: 2, + r_data: (0xB0u8, 0xC0u8 as i8), + w_addr: 2_hdl_u4, w_en: false, - w_data: (0xD0, 0xE0u8 as i8), + w_data: (0xD0u8, 0xE0u8 as i8), w_mask: (true, true), }, ]; - for ( - cycle, - expected @ IO { + for (cycle, expected) in io_cycles.into_iter().enumerate() { + #[hdl] + let IO { r_addr, r_en, r_data: _, @@ -681,37 +680,26 @@ fn test_memories() { w_en, w_data, w_mask, - }, - ) in io_cycles.into_iter().enumerate() - { - sim.write_bool_or_int(sim.io().r.addr, r_addr.cast_to_static()); - sim.write_bool(sim.io().r.en, r_en); - sim.write_bool_or_int(sim.io().w.addr, w_addr.cast_to_static()); - sim.write_bool(sim.io().w.en, w_en); - sim.write_bool_or_int(sim.io().w.data.0, w_data.0); - sim.write_bool_or_int(sim.io().w.data.1, w_data.1); - sim.write_bool(sim.io().w.mask.0, w_mask.0); - sim.write_bool(sim.io().w.mask.1, w_mask.1); - let io = IO { + } = expected; + sim.write(sim.io().r.addr, r_addr); + sim.write(sim.io().r.en, r_en); + sim.write(sim.io().w.addr, w_addr); + sim.write(sim.io().w.en, w_en); + sim.write(sim.io().w.data, w_data); + sim.write(sim.io().w.mask, w_mask); + let io = (#[hdl] + IO { r_addr, r_en, - r_data: ( - sim.read_bool_or_int(sim.io().r.data.0) - .to_bigint() - .try_into() - .expect("known to be in range"), - sim.read_bool_or_int(sim.io().r.data.1) - .to_bigint() - .try_into() - .expect("known to be in range"), - ), + r_data: sim.read(sim.io().r.data), w_addr, w_en, w_data, w_mask, - }; + }) + .to_sim_value(StaticType::TYPE); assert_eq!( - expected, + expected.to_sim_value(StaticType::TYPE), io, "vcd:\n{}\ncycle: {cycle}", String::from_utf8(writer.take()).unwrap(), @@ -739,7 +727,7 @@ fn test_memories() { #[hdl_module(outline_generated)] pub fn memories2() { #[hdl] - let rw: fayalite::memory::ReadWriteStruct, ConstUsize<3>> = m.input(); + let rw: ReadWriteStruct, ConstUsize<3>> = m.input(); #[hdl] let mut mem = memory_with_init([HdlSome(true); 5]); mem.read_latency(1); @@ -1012,9 +1000,9 @@ fn test_memories2() { #[hdl_module(outline_generated)] pub fn memories3() { #[hdl] - let r: fayalite::memory::ReadStruct, 8>, ConstUsize<3>> = m.input(); + let r: ReadStruct, 8>, ConstUsize<3>> = m.input(); #[hdl] - let w: fayalite::memory::WriteStruct, 8>, ConstUsize<3>> = m.input(); + let w: WriteStruct, 8>, ConstUsize<3>> = m.input(); #[hdl] let mut mem: MemBuilder, 8>> = memory(); mem.depth(8); diff --git a/crates/fayalite/tests/sim/expected/extern_module2.txt b/crates/fayalite/tests/sim/expected/extern_module2.txt index 96710fb..ec842ff 100644 --- a/crates/fayalite/tests/sim/expected/extern_module2.txt +++ b/crates/fayalite/tests/sim/expected/extern_module2.txt @@ -222,7 +222,9 @@ Simulation { }, value: SimValue { ty: Clock, - bits: 0x1, + value: OpaqueSimValue { + bits: 0x1_u1, + }, }, }, }, diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt index e290ace..5472950 100644 --- a/crates/fayalite/tests/sim/expected/ripple_counter.txt +++ b/crates/fayalite/tests/sim/expected/ripple_counter.txt @@ -826,7 +826,9 @@ Simulation { }, value: SimValue { ty: Clock, - bits: 0x0, + value: OpaqueSimValue { + bits: 0x0_u1, + }, }, }, }, @@ -921,7 +923,9 @@ Simulation { }, value: SimValue { ty: Clock, - bits: 0x0, + value: OpaqueSimValue { + bits: 0x0_u1, + }, }, }, }, @@ -1016,7 +1020,9 @@ Simulation { }, value: SimValue { ty: Clock, - bits: 0x0, + value: OpaqueSimValue { + bits: 0x0_u1, + }, }, }, },