diff --git a/crates/fayalite/src/clock.rs b/crates/fayalite/src/clock.rs index fe99653..711432b 100644 --- a/crates/fayalite/src/clock.rs +++ b/crates/fayalite/src/clock.rs @@ -4,7 +4,7 @@ use crate::{ expr::{Expr, ToExpr}, hdl, int::Bool, - reset::Reset, + reset::{Reset, ResetType}, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; @@ -88,9 +88,9 @@ impl ToClock for Expr { } #[hdl] -pub struct ClockDomain { +pub struct ClockDomain { pub clk: Clock, - pub rst: Reset, + pub rst: R, } impl ToClock for bool { diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index fa50852..f0008f4 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -17,6 +17,7 @@ use crate::{ Instance, ModuleIO, }, reg::Reg, + reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, ty::{CanonicalType, StaticType, Type, TypeWithDeref}, wire::Wire, }; @@ -209,7 +210,9 @@ expr_enum! { ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), - Reg(Reg), + Reg(Reg), + RegSync(Reg), + RegAsync(Reg), MemPort(MemPort), } } @@ -593,25 +596,42 @@ impl GetTarget for Wire { } } -impl ToExpr for Reg { +impl ToExpr for Reg { type Type = T; fn to_expr(&self) -> Expr { + struct Dispatch; + impl ResetTypeDispatch for Dispatch { + type Input = Reg; + type Output = ExprEnum; + + fn reset(self, input: Self::Input) -> Self::Output { + ExprEnum::Reg(input) + } + + fn sync_reset(self, input: Self::Input) -> Self::Output { + ExprEnum::RegSync(input) + } + + fn async_reset(self, input: Self::Input) -> Self::Output { + ExprEnum::RegAsync(input) + } + } Expr { - __enum: ExprEnum::Reg(self.canonical()).intern_sized(), + __enum: R::dispatch(self.canonical(), Dispatch).intern_sized(), __ty: self.ty(), __flow: self.flow(), } } } -impl ToLiteralBits for Reg { +impl ToLiteralBits for Reg { fn to_literal_bits(&self) -> Result, NotALiteralExpr> { Err(NotALiteralExpr) } } -impl GetTarget for Reg { +impl GetTarget for Reg { fn target(&self) -> Option> { Some(Intern::intern_sized(self.canonical().into())) } diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index 849be00..8f39e13 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -8,6 +8,7 @@ use crate::{ memory::{DynPortType, MemPort}, module::{Instance, ModuleIO, TargetName}, reg::Reg, + reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, wire::Wire, @@ -127,6 +128,7 @@ macro_rules! impl_target_base { $(#[$enum_meta:meta])* $enum_vis:vis enum $TargetBase:ident { $( + $(#[from = $from:ident])? #[is = $is_fn:ident] #[to = $to_fn:ident] $(#[$variant_meta:meta])* @@ -150,19 +152,19 @@ macro_rules! impl_target_base { } } - $( + $($( impl From<$VariantTy> for $TargetBase { - fn from(value: $VariantTy) -> Self { + fn $from(value: $VariantTy) -> Self { Self::$Variant(value) } } impl From<$VariantTy> for Target { - fn from(value: $VariantTy) -> Self { + fn $from(value: $VariantTy) -> Self { $TargetBase::$Variant(value).into() } } - )* + )*)? impl $TargetBase { $( @@ -199,24 +201,63 @@ macro_rules! impl_target_base { impl_target_base! { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum TargetBase { + #[from = from] #[is = is_module_io] #[to = module_io] ModuleIO(ModuleIO), + #[from = from] #[is = is_mem_port] #[to = mem_port] MemPort(MemPort), #[is = is_reg] #[to = reg] - Reg(Reg), + Reg(Reg), + #[is = is_reg_sync] + #[to = reg_sync] + RegSync(Reg), + #[is = is_reg_async] + #[to = reg_async] + RegAsync(Reg), + #[from = from] #[is = is_wire] #[to = wire] Wire(Wire), + #[from = from] #[is = is_instance] #[to = instance] Instance(Instance), } } +impl From> for TargetBase { + fn from(value: Reg) -> Self { + struct Dispatch; + impl ResetTypeDispatch for Dispatch { + type Input = Reg; + type Output = TargetBase; + + fn reset(self, input: Self::Input) -> Self::Output { + TargetBase::Reg(input) + } + + fn sync_reset(self, input: Self::Input) -> Self::Output { + TargetBase::RegSync(input) + } + + fn async_reset(self, input: Self::Input) -> Self::Output { + TargetBase::RegAsync(input) + } + } + R::dispatch(value, Dispatch) + } +} + +impl From> for Target { + fn from(value: Reg) -> Self { + TargetBase::from(value).into() + } +} + impl fmt::Display for TargetBase { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.target_name()) @@ -229,6 +270,8 @@ impl TargetBase { TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None), TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())), TargetBase::Reg(v) => TargetName(v.scoped_name(), None), + TargetBase::RegSync(v) => TargetName(v.scoped_name(), None), + TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None), TargetBase::Wire(v) => TargetName(v.scoped_name(), None), TargetBase::Instance(v) => TargetName(v.scoped_name(), None), } @@ -238,6 +281,8 @@ impl TargetBase { TargetBase::ModuleIO(v) => v.ty(), TargetBase::MemPort(v) => v.ty().canonical(), TargetBase::Reg(v) => v.ty(), + TargetBase::RegSync(v) => v.ty(), + TargetBase::RegAsync(v) => v.ty(), TargetBase::Wire(v) => v.ty(), TargetBase::Instance(v) => v.ty().canonical(), } diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index bc75ccc..ea76cf8 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -31,7 +31,7 @@ use crate::{ StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, }, - reset::{AsyncReset, Reset, SyncReset}, + reset::{AsyncReset, Reset, ResetType, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, util::{ @@ -1739,6 +1739,14 @@ impl<'a> Exporter<'a> { assert!(!const_ty, "not a constant"); self.module.ns.get(expr.scoped_name().1).to_string() } + ExprEnum::RegSync(expr) => { + assert!(!const_ty, "not a constant"); + self.module.ns.get(expr.scoped_name().1).to_string() + } + ExprEnum::RegAsync(expr) => { + assert!(!const_ty, "not a constant"); + self.module.ns.get(expr.scoped_name().1).to_string() + } ExprEnum::MemPort(expr) => { assert!(!const_ty, "not a constant"); let mem_name = self.module.ns.get(expr.mem_name().1); @@ -1848,6 +1856,8 @@ impl<'a> Exporter<'a> { self.module.ns.get(v.mem_name().1) } TargetBase::Reg(v) => self.module.ns.get(v.name_id()), + TargetBase::RegSync(v) => self.module.ns.get(v.name_id()), + TargetBase::RegAsync(v) => self.module.ns.get(v.name_id()), TargetBase::Wire(v) => self.module.ns.get(v.name_id()), TargetBase::Instance(v) => self.module.ns.get(v.name_id()), }; @@ -1956,6 +1966,37 @@ impl<'a> Exporter<'a> { drop(memory_indent); Ok(body) } + fn stmt_reg( + &mut self, + stmt_reg: StmtReg, + module_name: Ident, + definitions: &RcDefinitions, + body: &mut String, + ) { + let StmtReg { annotations, reg } = stmt_reg; + let indent = self.indent; + self.targeted_annotations(module_name, vec![], &annotations); + let name = self.module.ns.get(reg.name_id()); + let ty = self.type_state.ty(reg.ty()); + let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false); + if let Some(init) = reg.init() { + let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false); + let init = self.expr(init, definitions, false); + writeln!( + body, + "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", + FileInfo::new(reg.source_location()), + ) + .unwrap(); + } else { + writeln!( + body, + "{indent}reg {name}: {ty}, {clk}{}", + FileInfo::new(reg.source_location()), + ) + .unwrap(); + } + } fn block( &mut self, module: Interned>, @@ -2126,30 +2167,14 @@ impl<'a> Exporter<'a> { ) .unwrap(); } - Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations, reg })) => { - self.targeted_annotations(module_name, vec![], &annotations); - let name = self.module.ns.get(reg.name_id()); - let ty = self.type_state.ty(reg.ty()); - let clk = - self.expr(Expr::canonical(reg.clock_domain().clk), &definitions, false); - if let Some(init) = reg.init() { - let rst = - self.expr(Expr::canonical(reg.clock_domain().rst), &definitions, false); - let init = self.expr(init, &definitions, false); - writeln!( - body, - "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", - FileInfo::new(reg.source_location()), - ) - .unwrap(); - } else { - writeln!( - body, - "{indent}reg {name}: {ty}, {clk}{}", - FileInfo::new(reg.source_location()), - ) - .unwrap(); - } + Stmt::Declaration(StmtDeclaration::Reg(stmt_reg)) => { + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); + } + Stmt::Declaration(StmtDeclaration::RegSync(stmt_reg)) => { + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); + } + Stmt::Declaration(StmtDeclaration::RegAsync(stmt_reg)) => { + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); } Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations, diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 915bf43..5a18ac9 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -20,6 +20,7 @@ use crate::{ intern::{Intern, Interned}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, reg::Reg, + reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, util::ScopedRef, @@ -350,7 +351,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -362,7 +363,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta])* $vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $( - #[is = $is_fn, as_ref = $as_ref_fn] + #[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?] $(#[$variant_meta])* $Variant($VariantTy), )* @@ -389,7 +390,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -401,22 +402,22 @@ macro_rules! wrapper_enum { $(#[$enum_meta])* $vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $( - #[is = $is_fn, as_ref = $as_ref_fn] + #[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?] $(#[$variant_meta])* $Variant($VariantTy), )* } } - $( + $($( wrapper_enum! { impl $T_to From<$VariantTy> for $to_type { - fn from(value: $VariantTy) -> Self { + fn $from(value: $VariantTy) -> Self { $enum_name::$Variant(value).into() } } } - )* + )?)* }; ( #[impl()] @@ -424,7 +425,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -466,12 +467,12 @@ pub struct StmtWire { impl Copy for StmtWire {} #[derive(Hash, Clone, PartialEq, Eq, Debug)] -pub struct StmtReg { +pub struct StmtReg { pub annotations: S::StmtAnnotations, - pub reg: Reg, + pub reg: Reg, } -impl Copy for StmtReg {} +impl Copy for StmtReg {} #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct StmtInstance { @@ -489,22 +490,57 @@ wrapper_enum! { #[to(() StmtDeclaration, () Stmt)] #[derive(Clone, PartialEq, Eq, Hash)] pub enum StmtDeclaration { - #[is = is_wire, as_ref = wire] + #[is = is_wire, as_ref = wire, from = from] Wire(StmtWire), #[is = is_reg, as_ref = reg] - Reg(StmtReg), - #[is = is_instance, as_ref = instance] + Reg(StmtReg), + #[is = is_reg_sync, as_ref = reg_sync] + RegSync(StmtReg), + #[is = is_reg_async, as_ref = reg_async] + RegAsync(StmtReg), + #[is = is_instance, as_ref = instance, from = from] Instance(StmtInstance), } } impl Copy for StmtDeclaration {} +impl From> for Stmt { + fn from(value: StmtReg) -> Self { + StmtDeclaration::from(value).into() + } +} + +impl From> for StmtDeclaration { + fn from(value: StmtReg) -> Self { + struct Dispatch(PhantomData); + impl ResetTypeDispatch for Dispatch { + type Input = StmtReg; + type Output = StmtDeclaration; + + fn reset(self, input: Self::Input) -> Self::Output { + StmtDeclaration::Reg(input) + } + + fn sync_reset(self, input: Self::Input) -> Self::Output { + StmtDeclaration::RegSync(input) + } + + fn async_reset(self, input: Self::Input) -> Self::Output { + StmtDeclaration::RegAsync(input) + } + } + R::dispatch(value, Dispatch(PhantomData)) + } +} + impl StmtDeclaration { pub fn annotations(&self) -> S::StmtAnnotations { match self { StmtDeclaration::Wire(v) => v.annotations, StmtDeclaration::Reg(v) => v.annotations, + StmtDeclaration::RegSync(v) => v.annotations, + StmtDeclaration::RegAsync(v) => v.annotations, StmtDeclaration::Instance(v) => v.annotations, } } @@ -512,6 +548,8 @@ impl StmtDeclaration { match self { StmtDeclaration::Wire(v) => v.wire.source_location(), StmtDeclaration::Reg(v) => v.reg.source_location(), + StmtDeclaration::RegSync(v) => v.reg.source_location(), + StmtDeclaration::RegAsync(v) => v.reg.source_location(), StmtDeclaration::Instance(v) => v.instance.source_location(), } } @@ -519,20 +557,26 @@ impl StmtDeclaration { match self { StmtDeclaration::Wire(v) => v.wire.scoped_name(), StmtDeclaration::Reg(v) => v.reg.scoped_name(), + StmtDeclaration::RegSync(v) => v.reg.scoped_name(), + StmtDeclaration::RegAsync(v) => v.reg.scoped_name(), StmtDeclaration::Instance(v) => v.instance.scoped_name(), } } pub fn sub_stmt_blocks(&self) -> &[S::Block] { match self { - StmtDeclaration::Wire(_) | StmtDeclaration::Reg(_) | StmtDeclaration::Instance(_) => { - &[] - } + StmtDeclaration::Wire(_) + | StmtDeclaration::Reg(_) + | StmtDeclaration::RegSync(_) + | StmtDeclaration::RegAsync(_) + | StmtDeclaration::Instance(_) => &[], } } pub fn canonical_ty(&self) -> CanonicalType { match self { StmtDeclaration::Wire(v) => v.wire.ty(), StmtDeclaration::Reg(v) => v.reg.ty(), + StmtDeclaration::RegSync(v) => v.reg.ty(), + StmtDeclaration::RegAsync(v) => v.reg.ty(), StmtDeclaration::Instance(v) => CanonicalType::Bundle(v.instance.ty()), } } @@ -543,15 +587,15 @@ wrapper_enum! { #[to(() Stmt)] #[derive(Clone, PartialEq, Eq, Hash)] pub enum Stmt { - #[is = is_connect, as_ref = connect] + #[is = is_connect, as_ref = connect, from = from] Connect(StmtConnect), - #[is = is_formal, as_ref = formal] + #[is = is_formal, as_ref = formal, from = from] Formal(StmtFormal), - #[is = is_if, as_ref = if_] + #[is = is_if, as_ref = if_, from = from] If(StmtIf), - #[is = is_match, as_ref = match_] + #[is = is_match, as_ref = match_, from = from] Match(StmtMatch), - #[is = is_declaration, as_ref = declaration] + #[is = is_declaration, as_ref = declaration, from = from] Declaration(StmtDeclaration), } } @@ -982,6 +1026,14 @@ impl From> for NormalModuleBody { annotations: (), reg, }) => StmtReg { annotations, reg }.into(), + StmtDeclaration::RegSync(StmtReg { + annotations: (), + reg, + }) => StmtReg { annotations, reg }.into(), + StmtDeclaration::RegAsync(StmtReg { + annotations: (), + reg, + }) => StmtReg { annotations, reg }.into(), StmtDeclaration::Instance(StmtInstance { annotations: (), instance, @@ -1685,6 +1737,14 @@ impl AssertValidityState { annotations: _, reg, })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + Stmt::Declaration(StmtDeclaration::RegSync(StmtReg { + annotations: _, + reg, + })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg { + annotations: _, + reg, + })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations: _, instance, @@ -1866,10 +1926,10 @@ impl RegBuilder { } impl RegBuilder<(), I, T> { - pub fn clock_domain( + pub fn clock_domain( self, - clock_domain: impl ToExpr, - ) -> RegBuilder, I, T> { + clock_domain: impl ToExpr>, + ) -> RegBuilder>, I, T> { let Self { name, source_location, @@ -1887,7 +1947,7 @@ impl RegBuilder<(), I, T> { } } -impl RegBuilder, Option>, T> { +impl RegBuilder>, Option>, T> { #[track_caller] pub fn build(self) -> Expr { let Self { @@ -2212,6 +2272,16 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { reg, } .into(), + TargetBase::RegSync(reg) => StmtReg { + annotations: (), + reg, + } + .into(), + TargetBase::RegAsync(reg) => StmtReg { + annotations: (), + reg, + } + .into(), TargetBase::Wire(wire) => StmtWire { annotations: (), wire, @@ -2698,5 +2768,5 @@ pub struct TargetInInstantiatedModule { #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct ExprInInstantiatedModule { pub instantiated_module: InstantiatedModule, - pub target: Expr, + pub expr: Expr, } diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index bb57cf0..4eb0d0c 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -764,7 +764,9 @@ impl Folder for State { | ExprEnum::ModuleIO(_) | ExprEnum::Instance(_) | ExprEnum::Wire(_) - | ExprEnum::Reg(_) => op.default_fold(self), + | ExprEnum::Reg(_) + | ExprEnum::RegSync(_) + | ExprEnum::RegAsync(_) => op.default_fold(self), } } diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 2e1e48f..97de4fc 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -29,7 +29,7 @@ use crate::{ StmtInstance, StmtMatch, StmtReg, StmtWire, }, reg::Reg, - reset::{AsyncReset, Reset, SyncReset}, + reset::{AsyncReset, Reset, ResetType, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, wire::Wire, diff --git a/crates/fayalite/src/reg.rs b/crates/fayalite/src/reg.rs index 8f757f2..20e0b94 100644 --- a/crates/fayalite/src/reg.rs +++ b/crates/fayalite/src/reg.rs @@ -5,21 +5,22 @@ use crate::{ expr::{Expr, Flow}, intern::Interned, module::{NameId, ScopedNameId}, + reset::{Reset, ResetType}, source_location::SourceLocation, ty::{CanonicalType, Type}, }; use std::fmt; #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Reg { +pub struct Reg { name: ScopedNameId, source_location: SourceLocation, ty: T, - clock_domain: Expr, + clock_domain: Expr>, init: Option>, } -impl fmt::Debug for Reg { +impl fmt::Debug for Reg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { name, @@ -37,8 +38,8 @@ impl fmt::Debug for Reg { } } -impl Reg { - pub fn canonical(&self) -> Reg { +impl Reg { + pub fn canonical(&self) -> Reg { let Self { name, source_location, @@ -59,7 +60,7 @@ impl Reg { scoped_name: ScopedNameId, source_location: SourceLocation, ty: T, - clock_domain: Expr, + clock_domain: Expr>, init: Option>, ) -> Self { assert!( @@ -98,7 +99,7 @@ impl Reg { pub fn scoped_name(&self) -> ScopedNameId { self.name } - pub fn clock_domain(&self) -> Expr { + pub fn clock_domain(&self) -> Expr> { self.clock_domain } pub fn init(&self) -> Option> { diff --git a/crates/fayalite/src/reset.rs b/crates/fayalite/src/reset.rs index 70d5f02..0dd6df8 100644 --- a/crates/fayalite/src/reset.rs +++ b/crates/fayalite/src/reset.rs @@ -11,10 +11,21 @@ mod sealed { pub trait ResetTypeSealed {} } -pub trait ResetType: StaticType + sealed::ResetTypeSealed {} +pub trait ResetType: StaticType + sealed::ResetTypeSealed { + fn dispatch(input: D::Input, dispatch: D) -> D::Output; +} + +pub trait ResetTypeDispatch: Sized { + type Input; + type Output; + + fn reset(self, input: Self::Input) -> Self::Output; + fn sync_reset(self, input: Self::Input) -> Self::Output; + fn async_reset(self, input: Self::Input) -> Self::Output; +} macro_rules! reset_type { - ($name:ident, $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal) => { + ($name:ident, $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal, $dispatch_fn:ident) => { #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct $name; @@ -67,7 +78,14 @@ macro_rules! reset_type { impl sealed::ResetTypeSealed for $name {} - impl ResetType for $name {} + impl ResetType for $name { + fn dispatch( + input: D::Input, + dispatch: D, + ) -> D::Output { + dispatch.$dispatch_fn(input) + } + } pub trait $Trait { fn $trait_fn(&self) -> Expr<$name>; @@ -99,12 +117,13 @@ macro_rules! reset_type { }; } -reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true); -reset_type!(SyncReset, ToSyncReset::to_sync_reset, true); +reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true, async_reset); +reset_type!(SyncReset, ToSyncReset::to_sync_reset, true, sync_reset); reset_type!( Reset, ToReset::to_reset, - false // Reset is not castable from bits because we don't know if it's async or sync + false, // Reset is not castable from bits because we don't know if it's async or sync + reset ); impl ToSyncReset for bool { diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 1bed47d..4780ea2 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -1405,6 +1405,18 @@ impl Compiler { ty: reg.ty(), } .into(), + TargetBase::RegSync(reg) => TraceReg { + name: reg.name(), + child: self.make_trace_decl_child(target, reg.name()).intern(), + ty: reg.ty(), + } + .into(), + TargetBase::RegAsync(reg) => TraceReg { + name: reg.name(), + child: self.make_trace_decl_child(target, reg.name()).intern(), + ty: reg.ty(), + } + .into(), TargetBase::Wire(wire) => TraceWire { name: wire.name(), child: self.make_trace_decl_child(target, wire.name()).intern(), @@ -1452,7 +1464,7 @@ impl Compiler { | TargetBase::MemPort(_) | TargetBase::Wire(_) | TargetBase::Instance(_) => None, - TargetBase::Reg(_) => { + TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => { let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( "{:?}.{:?}$next", target.instantiated_module, @@ -2412,6 +2424,18 @@ impl Compiler { target: expr.into(), }) .into(), + ExprEnum::RegSync(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::RegAsync(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), ExprEnum::MemPort(expr) => self .compile_value(TargetInInstantiatedModule { instantiated_module, @@ -2606,6 +2630,8 @@ impl Compiler { let target_base: TargetBase = match &declaration { StmtDeclaration::Wire(v) => v.wire.into(), StmtDeclaration::Reg(v) => v.reg.into(), + StmtDeclaration::RegSync(v) => v.reg.into(), + StmtDeclaration::RegAsync(v) => v.reg.into(), StmtDeclaration::Instance(v) => v.instance.into(), }; let target = TargetInInstantiatedModule { @@ -2619,6 +2645,12 @@ impl Compiler { StmtDeclaration::Reg(StmtReg { annotations, reg }) => { todo!(); } + StmtDeclaration::RegSync(StmtReg { annotations, reg }) => { + todo!(); + } + StmtDeclaration::RegAsync(StmtReg { annotations, reg }) => { + todo!(); + } StmtDeclaration::Instance(StmtInstance { annotations, instance, diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index 182efd9..3eff1f5 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -1047,9 +1047,9 @@ "clock_domain()": "Visible", "init()": "Visible" }, - "generics": "", - "fold_where": "T: Fold", - "visit_where": "T: Visit" + "generics": "", + "fold_where": "T: Fold, R: Fold", + "visit_where": "T: Visit, R: Visit" }, "Wire": { "data": { @@ -1078,6 +1078,8 @@ "$kind": "Enum", "Wire": "Visible", "Reg": "Visible", + "RegSync": "Visible", + "RegAsync": "Visible", "Instance": "Visible" } }, @@ -1136,7 +1138,10 @@ "$kind": "Struct", "annotations": "Visible", "reg": "Visible" - } + }, + "generics": "", + "fold_where": "R: Fold", + "visit_where": "R: Visit" }, "StmtWire": { "data": { @@ -1219,6 +1224,8 @@ "ModuleIO": "Visible", "MemPort": "Visible", "Reg": "Visible", + "RegSync": "Visible", + "RegAsync": "Visible", "Wire": "Visible", "Instance": "Visible" }