diff --git a/interp/Cargo.toml b/interp/Cargo.toml index 537518f77..8d99d1a84 100644 --- a/interp/Cargo.toml +++ b/interp/Cargo.toml @@ -48,7 +48,6 @@ baa = { version = "0.14.0", features = ["bigint", "serde1", "fraction1"] } fst-writer = "0.2.1" bon = "2.3" - [dev-dependencies] proptest = "1.0.0" diff --git a/interp/src/flatten/primitives/combinational.rs b/interp/src/flatten/primitives/combinational.rs index da6ddb1d5..8df70e435 100644 --- a/interp/src/flatten/primitives/combinational.rs +++ b/interp/src/flatten/primitives/combinational.rs @@ -11,6 +11,7 @@ use baa::{BitVecOps, BitVecValue}; use super::prim_trait::UpdateResult; +#[derive(Clone)] pub struct StdConst { value: BitVecValue, out: GlobalPortIdx, @@ -44,8 +45,13 @@ impl Primitive for StdConst { fn has_stateful(&self) -> bool { false } + + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } } +#[derive(Clone)] pub struct StdMux { base: GlobalPortIdx, } @@ -80,6 +86,10 @@ impl Primitive for StdMux { fn has_stateful(&self) -> bool { false } + + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } } comb_primitive!(StdNot(input [0]) -> (out [1]) { @@ -275,6 +285,7 @@ comb_primitive!(StdUnsynSmod[WIDTH](left [0], right [1]) -> (out [2]) { Ok(Some(BitVecValue::from_big_int(&res, WIDTH))) }); +#[derive(Clone)] pub struct StdUndef(GlobalPortIdx); impl StdUndef { @@ -288,4 +299,8 @@ impl Primitive for StdUndef { port_map.write_undef(self.0)?; Ok(UpdateStatus::Unchanged) } + + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/interp/src/flatten/primitives/macros.rs b/interp/src/flatten/primitives/macros.rs index 7a34274e4..bf75c6f1b 100644 --- a/interp/src/flatten/primitives/macros.rs +++ b/interp/src/flatten/primitives/macros.rs @@ -102,6 +102,12 @@ macro_rules! comb_primitive { false } + fn clone_boxed(&self) -> Box { + Box::new(Self { + base_port: self.base_port, + $($($param: self.$param,)+)? + }) + } } }; diff --git a/interp/src/flatten/primitives/prim_trait.rs b/interp/src/flatten/primitives/prim_trait.rs index ecfb0b2e5..199adce45 100644 --- a/interp/src/flatten/primitives/prim_trait.rs +++ b/interp/src/flatten/primitives/prim_trait.rs @@ -134,6 +134,8 @@ pub trait Primitive { fn dump_memory_state(&self) -> Option> { None } + + fn clone_boxed(&self) -> Box; } pub trait RaceDetectionPrimitive: Primitive { @@ -158,10 +160,13 @@ pub trait RaceDetectionPrimitive: Primitive { /// Get a reference to the underlying primitive. Unfortunately cannot add an /// optional default implementation due to size rules fn as_primitive(&self) -> &dyn Primitive; + + fn clone_boxed_rd(&self) -> Box; } /// An empty primitive implementation used for testing. It does not do anything /// and has no ports of any kind +#[derive(Clone, Copy)] pub struct DummyPrimitive; impl DummyPrimitive { @@ -170,4 +175,8 @@ impl DummyPrimitive { } } -impl Primitive for DummyPrimitive {} +impl Primitive for DummyPrimitive { + fn clone_boxed(&self) -> Box { + Box::new(*self) + } +} diff --git a/interp/src/flatten/primitives/stateful/math.rs b/interp/src/flatten/primitives/stateful/math.rs index 30e659810..c8fb091e4 100644 --- a/interp/src/flatten/primitives/stateful/math.rs +++ b/interp/src/flatten/primitives/stateful/math.rs @@ -10,6 +10,7 @@ use crate::flatten::{ use baa::{BitVecOps, BitVecValue, WidthInt}; use num_traits::Euclid; +#[derive(Clone)] pub struct StdMultPipe { base_port: GlobalPortIdx, pipeline: ShiftBuffer<(PortValue, PortValue), DEPTH>, @@ -32,6 +33,10 @@ impl StdMultPipe { } impl Primitive for StdMultPipe { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; out: Self::OUT, done: Self::DONE]; @@ -106,6 +111,7 @@ impl Primitive for StdMultPipe { } } +#[derive(Clone)] pub struct StdDivPipe { base_port: GlobalPortIdx, pipeline: ShiftBuffer<(PortValue, PortValue), DEPTH>, @@ -132,6 +138,10 @@ impl StdDivPipe { impl Primitive for StdDivPipe { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; out_quot: Self::OUT_QUOTIENT, @@ -253,6 +263,10 @@ impl Sqrt { } impl Primitive for Sqrt { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; out: Self::OUT, done: Self::DONE]; @@ -309,6 +323,7 @@ impl Primitive for Sqrt { } } +#[derive(Clone)] pub struct FxpMultPipe { base_port: GlobalPortIdx, pipeline: ShiftBuffer<(PortValue, PortValue), DEPTH>, @@ -339,6 +354,10 @@ impl FxpMultPipe { } impl Primitive for FxpMultPipe { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; out: Self::OUT, done: Self::DONE]; @@ -422,6 +441,7 @@ impl Primitive for FxpMultPipe { } } +#[derive(Clone)] pub struct FxpDivPipe { base_port: GlobalPortIdx, pipeline: ShiftBuffer<(PortValue, PortValue), DEPTH>, @@ -460,6 +480,10 @@ impl FxpDivPipe { impl Primitive for FxpDivPipe { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; out_quot: Self::OUT_QUOTIENT, diff --git a/interp/src/flatten/primitives/stateful/memories.rs b/interp/src/flatten/primitives/stateful/memories.rs index 7b2f5680b..8365907f2 100644 --- a/interp/src/flatten/primitives/stateful/memories.rs +++ b/interp/src/flatten/primitives/stateful/memories.rs @@ -27,6 +27,7 @@ use crate::{ use baa::{BitVecOps, BitVecValue, WidthInt}; +#[derive(Clone)] pub struct StdReg { base_port: GlobalPortIdx, internal_state: ValueWithClock, @@ -55,6 +56,10 @@ impl StdReg { } impl Primitive for StdReg { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_cycle(&mut self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; input: Self::IN, @@ -139,6 +144,10 @@ impl Primitive for StdReg { } impl RaceDetectionPrimitive for StdReg { + fn clone_boxed_rd(&self) -> Box { + Box::new(self.clone()) + } + fn as_primitive(&self) -> &dyn Primitive { self } @@ -176,6 +185,7 @@ impl RaceDetectionPrimitive for StdReg { } } +#[derive(Clone)] pub struct MemDx { shape: Shape, } @@ -389,6 +399,7 @@ impl MemDx { } } +#[derive(Clone)] pub struct CombMem { base_port: GlobalPortIdx, internal_state: Vec, @@ -508,6 +519,10 @@ impl CombMem { } impl Primitive for CombMem { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { let addr: Option = self .addresser @@ -609,6 +624,10 @@ impl Primitive for CombMem { } impl RaceDetectionPrimitive for CombMem { + fn clone_boxed_rd(&self) -> Box { + Box::new(self.clone()) + } + fn as_primitive(&self) -> &dyn Primitive { self } @@ -674,6 +693,7 @@ impl RaceDetectionPrimitive for CombMem { } } +#[derive(Clone)] pub struct SeqMem { base_port: GlobalPortIdx, internal_state: Vec, @@ -812,6 +832,10 @@ impl SeqMem { } impl Primitive for SeqMem { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { let done_signal = port_map.insert_val_general( self.done(), @@ -915,6 +939,10 @@ impl Primitive for SeqMem { } impl RaceDetectionPrimitive for SeqMem { + fn clone_boxed_rd(&self) -> Box { + Box::new(self.clone()) + } + fn as_primitive(&self) -> &dyn Primitive { self } diff --git a/interp/src/flatten/primitives/utils.rs b/interp/src/flatten/primitives/utils.rs index 6b91e17a3..51ab75fd5 100644 --- a/interp/src/flatten/primitives/utils.rs +++ b/interp/src/flatten/primitives/utils.rs @@ -38,6 +38,7 @@ pub(crate) fn int_sqrt(i: &BigUint) -> BigUint { } /// A shift buffer of a fixed size +#[derive(Clone)] pub struct ShiftBuffer { buffer: VecDeque>, } diff --git a/interp/src/flatten/structures/environment/env.rs b/interp/src/flatten/structures/environment/env.rs index 479619a81..65769f4d1 100644 --- a/interp/src/flatten/structures/environment/env.rs +++ b/interp/src/flatten/structures/environment/env.rs @@ -156,6 +156,7 @@ pub(crate) type RefPortMap = IndexedMap>; pub(crate) type AssignmentRange = IndexRange; +#[derive(Clone)] pub(crate) struct ComponentLedger { pub(crate) index_bases: BaseIndices, pub(crate) comp_id: ComponentIdx, @@ -192,6 +193,24 @@ pub(crate) enum CellLedger { Component(ComponentLedger), } +impl Clone for CellLedger { + fn clone(&self) -> Self { + match self { + Self::Primitive { cell_dyn } => Self::Primitive { + cell_dyn: cell_dyn.clone_boxed(), + }, + Self::RaceDetectionPrimitive { cell_dyn } => { + Self::RaceDetectionPrimitive { + cell_dyn: cell_dyn.clone_boxed_rd(), + } + } + Self::Component(component_ledger) => { + Self::Component(component_ledger.clone()) + } + } + } +} + impl From for CellLedger { fn from(v: ComponentLedger) -> Self { Self::Component(v) @@ -302,7 +321,7 @@ impl PinnedPorts { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Environment + Clone> { /// A map from global port IDs to their current values. ports: PortMap, @@ -1285,24 +1304,44 @@ impl + Clone> Environment { } } +/// The core functionality of a simulator. Clonable. +#[derive(Clone)] +pub struct BaseSimulator + Clone> { + env: Environment, + conf: RuntimeConfig, +} + /// A wrapper struct for the environment that provides the functions used to /// simulate the actual program. /// /// This is just to keep the simulation logic under a different namespace than /// the environment to avoid confusion pub struct Simulator + Clone> { - env: Environment, + base: BaseSimulator, wave: Option, - conf: RuntimeConfig, } impl + Clone> Simulator { - pub fn new( - env: Environment, + pub fn build_simulator( + ctx: C, + data_file: &Option, wave_file: &Option, - conf: RuntimeConfig, - ) -> Self { - // open the wave form file and declare all signals + runtime_config: RuntimeConfig, + ) -> Result { + let data_dump = data_file + .as_ref() + .map(|path| { + let mut file = std::fs::File::open(path)?; + DataDump::deserialize(&mut file) + }) + // flip to a result of an option + .map_or(Ok(None), |res| res.map(Some))?; + let env = Environment::new( + ctx, + data_dump, + runtime_config.check_data_race, + runtime_config.get_logging_config(), + ); let wave = wave_file.as_ref().map(|p| match WaveWriter::open(p, &env) { Ok(w) => w, @@ -1310,9 +1349,120 @@ impl + Clone> Simulator { todo!("deal more gracefully with error: {err:?}") } }); - let mut output = Self { env, wave, conf }; - output.set_root_go_high(); - output + Ok(Self { + base: BaseSimulator::new(env, runtime_config), + wave, + }) + } + + pub fn is_done(&self) -> bool { + self.base.is_done() + } + + pub fn step(&mut self) -> CiderResult<()> { + self.base.step() + } + + pub fn converge(&mut self) -> CiderResult<()> { + self.base.converge() + } + + pub fn get_currently_running_groups( + &self, + ) -> impl Iterator + '_ { + self.base.get_currently_running_groups() + } + + pub fn is_group_running(&self, group_idx: GroupIdx) -> bool { + self.base.is_group_running(group_idx) + } + + pub fn print_pc(&self) { + self.base.print_pc(); + } + + pub fn format_cell_state( + &self, + cell_idx: GlobalCellIdx, + print_code: PrintCode, + name: Option<&str>, + ) -> Option { + self.base.format_cell_state(cell_idx, print_code, name) + } + + pub fn format_cell_ports( + &self, + cell_idx: GlobalCellIdx, + print_code: PrintCode, + name: Option<&str>, + ) -> String { + self.base.format_cell_ports(cell_idx, print_code, name) + } + + pub fn format_port_value( + &self, + port_idx: GlobalPortIdx, + print_code: PrintCode, + ) -> String { + self.base.format_port_value(port_idx, print_code) + } + + pub fn traverse_name_vec( + &self, + name: &[String], + ) -> Result { + self.base.traverse_name_vec(name) + } + + pub fn get_full_name(&self, nameable: N) -> String + where + N: GetFullName, + { + self.base.get_full_name(nameable) + } + + pub(crate) fn env(&self) -> &Environment { + self.base.env() + } + + /// Evaluate the entire program + pub fn run_program(&mut self) -> CiderResult<()> { + if self.base.conf.debug_logging { + info!(self.base.env().logger, "Starting program execution"); + } + + match self.base.run_program_inner(self.wave.as_mut()) { + Ok(_) => { + if self.base.conf.debug_logging { + info!(self.base.env().logger, "Finished program execution"); + } + Ok(()) + } + Err(e) => { + if self.base.conf.debug_logging { + slog::error!( + self.base.env().logger, + "Program execution failed with error: {}", + e.red() + ); + } + Err(e) + } + } + } + + pub fn dump_memories( + &self, + dump_registers: bool, + all_mems: bool, + ) -> DataDump { + self.base.dump_memories(dump_registers, all_mems) + } +} + +impl + Clone> BaseSimulator { + pub fn new(env: Environment, conf: RuntimeConfig) -> Self { + Self { env, conf } } pub(crate) fn env(&self) -> &Environment { @@ -1332,33 +1482,6 @@ impl + Clone> Simulator { self.env } - pub fn build_simulator( - ctx: C, - data_file: &Option, - wave_file: &Option, - runtime_config: RuntimeConfig, - ) -> Result { - let data_dump = data_file - .as_ref() - .map(|path| { - let mut file = std::fs::File::open(path)?; - DataDump::deserialize(&mut file) - }) - // flip to a result of an option - .map_or(Ok(None), |res| res.map(Some))?; - - Ok(Simulator::new( - Environment::new( - ctx, - data_dump, - runtime_config.check_data_race, - runtime_config.get_logging_config(), - ), - wave_file, - runtime_config, - )) - } - pub fn is_group_running(&self, group_idx: GroupIdx) -> bool { self.env.is_group_running(group_idx) } @@ -1418,7 +1541,7 @@ impl + Clone> Simulator { } // =========================== simulation functions =========================== -impl + Clone> Simulator { +impl + Clone> BaseSimulator { #[inline] fn lookup_global_port_id(&self, port: GlobalPortRef) -> GlobalPortIdx { match port { @@ -2161,43 +2284,20 @@ impl + Clone> Simulator { .unwrap_or_default() } - /// Evaluate the entire program - pub fn run_program(&mut self) -> CiderResult<()> { - if self.conf.debug_logging { - info!(self.env.logger, "Starting program execution"); - } - - match self.run_program_inner() { - Ok(_) => { - if self.conf.debug_logging { - info!(self.env.logger, "Finished program execution"); - } - Ok(()) - } - Err(e) => { - if self.conf.debug_logging { - slog::error!( - self.env.logger, - "Program execution failed with error: {}", - e.red() - ); - } - Err(e) - } - } - } - - fn run_program_inner(&mut self) -> Result<(), BoxedCiderError> { + pub fn run_program_inner( + &mut self, + mut wave: Option<&mut WaveWriter>, + ) -> Result<(), BoxedCiderError> { let mut time = 0; while !self.is_done() { - if let Some(wave) = self.wave.as_mut() { + if let Some(wave) = wave.as_mut() { wave.write_values(time, &self.env.ports)?; } // self.print_pc(); self.step()?; time += 1; } - if let Some(wave) = self.wave.as_mut() { + if let Some(wave) = wave { wave.write_values(time, &self.env.ports)?; } Ok(()) diff --git a/interp/src/flatten/structures/environment/mod.rs b/interp/src/flatten/structures/environment/mod.rs index f5133e74a..40808bfbe 100644 --- a/interp/src/flatten/structures/environment/mod.rs +++ b/interp/src/flatten/structures/environment/mod.rs @@ -5,7 +5,7 @@ mod program_counter; mod traverser; mod wave; -pub use env::{Environment, PortMap, Simulator}; +pub use env::{BaseSimulator, Environment, PortMap, Simulator}; pub use traverser::{Path, PathError, PathResolution}; pub(crate) use env::CellLedger; diff --git a/interp/src/flatten/structures/environment/program_counter.rs b/interp/src/flatten/structures/environment/program_counter.rs index 3ce817a84..dc8223d24 100644 --- a/interp/src/flatten/structures/environment/program_counter.rs +++ b/interp/src/flatten/structures/environment/program_counter.rs @@ -375,7 +375,7 @@ impl WithEntry { /// The program counter for the whole program execution. Wraps over a vector of /// the active leaf statements for each component instance. -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub(crate) struct ProgramCounter { vec: Vec, par_map: HashMap, diff --git a/interp/src/flatten/structures/indexed_map.rs b/interp/src/flatten/structures/indexed_map.rs index 137788b09..e3f24c315 100644 --- a/interp/src/flatten/structures/indexed_map.rs +++ b/interp/src/flatten/structures/indexed_map.rs @@ -4,7 +4,7 @@ use std::{ ops::{self, Index}, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct IndexedMap where K: IndexRef, @@ -143,6 +143,7 @@ where Self::new() } } + #[allow(dead_code)] pub struct IndexedMapRangeIterator<'range, 'data, K, D> where diff --git a/interp/src/flatten/structures/thread.rs b/interp/src/flatten/structures/thread.rs index 938990dba..8ca8a5bc9 100644 --- a/interp/src/flatten/structures/thread.rs +++ b/interp/src/flatten/structures/thread.rs @@ -9,7 +9,7 @@ use super::{ pub struct ThreadIdx(NonZeroU32); impl_index_nonzero!(ThreadIdx); -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ThreadInfo { parent: Option, clock_id: ClockIdx, @@ -25,7 +25,7 @@ impl ThreadInfo { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ThreadMap { map: IndexedMap, }