diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 16010cf..b8610e7 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -2641,3 +2641,50 @@ impl ModuleIO { self.ty } } + +#[derive(PartialEq, Eq, Hash, Clone, Copy)] +pub enum InstantiatedModule { + Base(Interned>), + Child { + parent: Interned, + instance: Interned>, + }, +} + +impl InstantiatedModule { + pub fn leaf_module(self) -> Interned> { + match self { + InstantiatedModule::Base(base) => base, + InstantiatedModule::Child { instance, .. } => instance.instantiated(), + } + } + fn write_path(self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InstantiatedModule::Base(base) => fmt::Debug::fmt(&base.name_id(), f), + InstantiatedModule::Child { parent, instance } => { + parent.write_path(f)?; + write!(f, ".{}", instance.name_id()) + } + } + } +} + +impl fmt::Debug for InstantiatedModule { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "InstantiatedModule(")?; + self.write_path(f)?; + write!(f, ": {})", self.leaf_module().name_id()) + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct TargetInInstantiatedModule { + pub instantiated_module: InstantiatedModule, + pub target: Target, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct ExprInInstantiatedModule { + pub instantiated_module: InstantiatedModule, + pub target: Expr, +} diff --git a/crates/fayalite/src/module/transform.rs b/crates/fayalite/src/module/transform.rs index 4117087..063a1a3 100644 --- a/crates/fayalite/src/module/transform.rs +++ b/crates/fayalite/src/module/transform.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +pub mod deduce_resets; pub mod simplify_enums; pub mod simplify_memories; pub mod visit; diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs new file mode 100644 index 0000000..dc01b33 --- /dev/null +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use hashbrown::{hash_map::Entry, HashMap}; +use petgraph::graph::{NodeIndex, UnGraph}; + +use crate::{ + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, + expr::target::{TargetPathArrayElement, TargetPathBundleField, TargetPathElement}, + intern::{Intern, Interned, Memoize}, + module::{ + AnnotatedModuleIO, ExprInInstantiatedModule, ExternModuleBody, InstantiatedModule, + ModuleBody, NormalModuleBody, TargetInInstantiatedModule, + }, + prelude::*, +}; +use std::fmt; + +#[derive(Debug)] +pub enum DeduceResetsError { + ResetIsNotDrivenByAsyncOrSync { target: TargetInInstantiatedModule }, +} + +impl fmt::Display for DeduceResetsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { target } => { + write!(f, "deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {target:?}") + } + } + } +} + +impl std::error::Error for DeduceResetsError {} + +impl From for std::io::Error { + fn from(value: DeduceResetsError) -> Self { + std::io::Error::new(std::io::ErrorKind::Other, value) + } +} + +#[derive(Debug)] +struct Node { + target: TargetInInstantiatedModule, + deduced_type: Option, +} + +#[derive(Debug)] +struct State { + base_module: Interned>, + transformed_exprs: + HashMap, ExprInInstantiatedModule>, + node_ids: HashMap>, + graph: UnGraph, + fallback_to_sync_reset: bool, +} + +fn type_contains_any_undeduced_resets(ty: CanonicalType) -> bool { + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + struct MyMemoize; + impl Memoize for MyMemoize { + type Input = CanonicalType; + type InputOwned = CanonicalType; + type Output = bool; + + fn inner(self, input: &Self::Input) -> Self::Output { + match input { + CanonicalType::UInt(_) => false, + CanonicalType::SInt(_) => false, + CanonicalType::Bool(_) => false, + CanonicalType::Array(ty) => type_contains_any_undeduced_resets(ty.element()), + CanonicalType::Enum(ty) => { + ty.variants().iter().any(|EnumVariant { ty, .. }| { + ty.is_some_and(|ty| type_contains_any_undeduced_resets(ty)) + }) + } + CanonicalType::Bundle(ty) => ty + .fields() + .iter() + .any(|&BundleField { ty, .. }| type_contains_any_undeduced_resets(ty)), + CanonicalType::AsyncReset(_) => false, + CanonicalType::SyncReset(_) => false, + CanonicalType::Reset(_) => true, + CanonicalType::Clock(_) => false, + } + } + } + MyMemoize.get_owned(ty) +} + +impl State { + fn add_target_to_graph_recursive( + &mut self, + target: TargetInInstantiatedModule, + ) -> NodeIndex { + let entry = match self.node_ids.entry(target) { + Entry::Vacant(entry) => entry, + Entry::Occupied(entry) => { + return *entry.get(); + } + }; + let ty = target.target.canonical_ty(); + let node_id = self.graph.add_node(Node { + target, + deduced_type: type_contains_any_undeduced_resets(ty).then_some(ty), + }); + entry.insert(node_id); + match target.target.canonical_ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Clock(_) => {} + CanonicalType::Array(ty) => { + for index in 0..ty.len() { + self.add_target_to_graph_recursive(TargetInInstantiatedModule { + instantiated_module: target.instantiated_module, + target: target.target.join( + TargetPathElement::from(TargetPathArrayElement { index }) + .intern_sized(), + ), + }); + } + } + CanonicalType::Enum(_) => {} + CanonicalType::Bundle(ty) => { + for BundleField { name, .. } in ty.fields() { + self.add_target_to_graph_recursive(TargetInInstantiatedModule { + instantiated_module: target.instantiated_module, + target: target.target.join( + TargetPathElement::from(TargetPathBundleField { name }).intern_sized(), + ), + }); + } + } + CanonicalType::Reset(_) => {} + } + node_id + } + fn build_graph_for_module(&mut self, instantiated_module: Interned) { + let Module { + name: _, + source_location: _, + body, + io_ty: _, + module_io, + module_annotations: _, + } = *instantiated_module.leaf_module(); + for AnnotatedModuleIO { + annotations: _, + module_io, + } in module_io + { + self.add_target_to_graph_recursive(TargetInInstantiatedModule { + instantiated_module: *instantiated_module, + target: module_io.into(), + }); + } + match body { + ModuleBody::Normal(NormalModuleBody { body }) => todo!(), + ModuleBody::Extern(ExternModuleBody { + verilog_name: _, + parameters: _, + }) => {} + } + } + fn deduce_types(&mut self) -> Result<(), DeduceResetsError> { + todo!() + } + fn transform_module(&mut self, module: Interned>) -> Interned> { + todo!() + } +} + +pub fn deduce_resets( + module: Interned>, + fallback_to_sync_reset: bool, +) -> Result>, DeduceResetsError> { + let mut state = State { + base_module: module, + transformed_exprs: HashMap::new(), + node_ids: HashMap::new(), + graph: UnGraph::new_undirected(), + fallback_to_sync_reset, + }; + state.build_graph_for_module(InstantiatedModule::Base(module).intern_sized()); + state.deduce_types()?; + Ok(state.transform_module(module)) +} diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index fb5a1e0..1bed47d 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -16,9 +16,9 @@ use crate::{ int::BoolOrIntType, intern::{Intern, Interned, Memoize}, module::{ - AnnotatedModuleIO, Block, Id, ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, - StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, - StmtWire, + AnnotatedModuleIO, Block, Id, InstantiatedModule, ModuleBody, NameId, NormalModuleBody, + ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, + StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, }, prelude::*, sim::{ @@ -68,47 +68,6 @@ struct Cond { source_location: SourceLocation, } -#[derive(PartialEq, Eq, Hash, Clone, Copy)] -enum InstantiatedModule { - Base(Interned>), - Child { - parent: Interned, - instance: Interned>, - }, -} - -impl InstantiatedModule { - fn leaf_module(self) -> Interned> { - match self { - InstantiatedModule::Base(base) => base, - InstantiatedModule::Child { instance, .. } => instance.instantiated(), - } - } - fn write_path(self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - InstantiatedModule::Base(base) => fmt::Debug::fmt(&base.name_id(), f), - InstantiatedModule::Child { parent, instance } => { - parent.write_path(f)?; - write!(f, ".{}", instance.name_id()) - } - } - } -} - -impl fmt::Debug for InstantiatedModule { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "InstantiatedModule(")?; - self.write_path(f)?; - write!(f, ": {})", self.leaf_module().name_id()) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct TargetInInstantiatedModule { - instantiated_module: InstantiatedModule, - target: Target, -} - #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] struct CompiledBundleField { offset: TypeIndex,