forked from libre-chip/fayalite
		
	make ClockDomain and Reg generic over reset type
This commit is contained in:
		
							parent
							
								
									89d84551f8
								
							
						
					
					
						commit
						9b5f1218fd
					
				
					 11 changed files with 306 additions and 85 deletions
				
			
		|  | @ -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<Clock> { | |||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct ClockDomain { | ||||
| pub struct ClockDomain<R: ResetType = Reset> { | ||||
|     pub clk: Clock, | ||||
|     pub rst: Reset, | ||||
|     pub rst: R, | ||||
| } | ||||
| 
 | ||||
| impl ToClock for bool { | ||||
|  |  | |||
|  | @ -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<CanonicalType>), | ||||
|         Instance(Instance<Bundle>), | ||||
|         Wire(Wire<CanonicalType>), | ||||
|         Reg(Reg<CanonicalType>), | ||||
|         Reg(Reg<CanonicalType, Reset>), | ||||
|         RegSync(Reg<CanonicalType, SyncReset>), | ||||
|         RegAsync(Reg<CanonicalType, AsyncReset>), | ||||
|         MemPort(MemPort<DynPortType>), | ||||
|     } | ||||
| } | ||||
|  | @ -593,25 +596,42 @@ impl<T: Type> GetTarget for Wire<T> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> ToExpr for Reg<T> { | ||||
| impl<T: Type, R: ResetType> ToExpr for Reg<T, R> { | ||||
|     type Type = T; | ||||
| 
 | ||||
|     fn to_expr(&self) -> Expr<Self::Type> { | ||||
|         struct Dispatch; | ||||
|         impl ResetTypeDispatch for Dispatch { | ||||
|             type Input<T: ResetType> = Reg<CanonicalType, T>; | ||||
|             type Output<T: ResetType> = ExprEnum; | ||||
| 
 | ||||
|             fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> { | ||||
|                 ExprEnum::Reg(input) | ||||
|             } | ||||
| 
 | ||||
|             fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> { | ||||
|                 ExprEnum::RegSync(input) | ||||
|             } | ||||
| 
 | ||||
|             fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> { | ||||
|                 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<T: Type> ToLiteralBits for Reg<T> { | ||||
| impl<T: Type, R: ResetType> ToLiteralBits for Reg<T, R> { | ||||
|     fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> { | ||||
|         Err(NotALiteralExpr) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> GetTarget for Reg<T> { | ||||
| impl<T: Type, R: ResetType> GetTarget for Reg<T, R> { | ||||
|     fn target(&self) -> Option<Interned<Target>> { | ||||
|         Some(Intern::intern_sized(self.canonical().into())) | ||||
|     } | ||||
|  |  | |||
|  | @ -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<CanonicalType>), | ||||
|         #[from = from] | ||||
|         #[is = is_mem_port] | ||||
|         #[to = mem_port] | ||||
|         MemPort(MemPort<DynPortType>), | ||||
|         #[is = is_reg] | ||||
|         #[to = reg] | ||||
|         Reg(Reg<CanonicalType>), | ||||
|         Reg(Reg<CanonicalType, Reset>), | ||||
|         #[is = is_reg_sync] | ||||
|         #[to = reg_sync] | ||||
|         RegSync(Reg<CanonicalType, SyncReset>), | ||||
|         #[is = is_reg_async] | ||||
|         #[to = reg_async] | ||||
|         RegAsync(Reg<CanonicalType, AsyncReset>), | ||||
|         #[from = from] | ||||
|         #[is = is_wire] | ||||
|         #[to = wire] | ||||
|         Wire(Wire<CanonicalType>), | ||||
|         #[from = from] | ||||
|         #[is = is_instance] | ||||
|         #[to = instance] | ||||
|         Instance(Instance<Bundle>), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<R: ResetType> From<Reg<CanonicalType, R>> for TargetBase { | ||||
|     fn from(value: Reg<CanonicalType, R>) -> Self { | ||||
|         struct Dispatch; | ||||
|         impl ResetTypeDispatch for Dispatch { | ||||
|             type Input<T: ResetType> = Reg<CanonicalType, T>; | ||||
|             type Output<T: ResetType> = TargetBase; | ||||
| 
 | ||||
|             fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> { | ||||
|                 TargetBase::Reg(input) | ||||
|             } | ||||
| 
 | ||||
|             fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> { | ||||
|                 TargetBase::RegSync(input) | ||||
|             } | ||||
| 
 | ||||
|             fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> { | ||||
|                 TargetBase::RegAsync(input) | ||||
|             } | ||||
|         } | ||||
|         R::dispatch(value, Dispatch) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<R: ResetType> From<Reg<CanonicalType, R>> for Target { | ||||
|     fn from(value: Reg<CanonicalType, R>) -> 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(), | ||||
|         } | ||||
|  |  | |||
|  | @ -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<R: ResetType>( | ||||
|         &mut self, | ||||
|         stmt_reg: StmtReg<R>, | ||||
|         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<Module<Bundle>>, | ||||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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<S: ModuleBuildingStatus = ModuleBuilt> { | |||
| impl Copy for StmtWire {} | ||||
| 
 | ||||
| #[derive(Hash, Clone, PartialEq, Eq, Debug)] | ||||
| pub struct StmtReg<S: ModuleBuildingStatus = ModuleBuilt> { | ||||
| pub struct StmtReg<R: ResetType, S: ModuleBuildingStatus = ModuleBuilt> { | ||||
|     pub annotations: S::StmtAnnotations, | ||||
|     pub reg: Reg<CanonicalType>, | ||||
|     pub reg: Reg<CanonicalType, R>, | ||||
| } | ||||
| 
 | ||||
| impl Copy for StmtReg {} | ||||
| impl<R: ResetType> Copy for StmtReg<R> {} | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||
| pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> { | ||||
|  | @ -489,22 +490,57 @@ wrapper_enum! { | |||
|     #[to((<S: ModuleBuildingStatus>) StmtDeclaration<S>, (<S: ModuleBuildingStatus>) Stmt<S>)] | ||||
|     #[derive(Clone, PartialEq, Eq, Hash)] | ||||
|     pub enum StmtDeclaration<S: ModuleBuildingStatus = ModuleBuilt> { | ||||
|         #[is = is_wire, as_ref = wire] | ||||
|         #[is = is_wire, as_ref = wire, from = from] | ||||
|         Wire(StmtWire<S>), | ||||
|         #[is = is_reg, as_ref = reg] | ||||
|         Reg(StmtReg<S>), | ||||
|         #[is = is_instance, as_ref = instance] | ||||
|         Reg(StmtReg<Reset, S>), | ||||
|         #[is = is_reg_sync, as_ref = reg_sync] | ||||
|         RegSync(StmtReg<SyncReset, S>), | ||||
|         #[is = is_reg_async, as_ref = reg_async] | ||||
|         RegAsync(StmtReg<AsyncReset, S>), | ||||
|         #[is = is_instance, as_ref = instance, from = from] | ||||
|         Instance(StmtInstance<S>), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Copy for StmtDeclaration {} | ||||
| 
 | ||||
| impl<S: ModuleBuildingStatus, R: ResetType> From<StmtReg<R, S>> for Stmt<S> { | ||||
|     fn from(value: StmtReg<R, S>) -> Self { | ||||
|         StmtDeclaration::from(value).into() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<S: ModuleBuildingStatus, R: ResetType> From<StmtReg<R, S>> for StmtDeclaration<S> { | ||||
|     fn from(value: StmtReg<R, S>) -> Self { | ||||
|         struct Dispatch<S>(PhantomData<S>); | ||||
|         impl<S: ModuleBuildingStatus> ResetTypeDispatch for Dispatch<S> { | ||||
|             type Input<T: ResetType> = StmtReg<T, S>; | ||||
|             type Output<T: ResetType> = StmtDeclaration<S>; | ||||
| 
 | ||||
|             fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> { | ||||
|                 StmtDeclaration::Reg(input) | ||||
|             } | ||||
| 
 | ||||
|             fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> { | ||||
|                 StmtDeclaration::RegSync(input) | ||||
|             } | ||||
| 
 | ||||
|             fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> { | ||||
|                 StmtDeclaration::RegAsync(input) | ||||
|             } | ||||
|         } | ||||
|         R::dispatch(value, Dispatch(PhantomData)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<S: ModuleBuildingStatus> StmtDeclaration<S> { | ||||
|     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<S: ModuleBuildingStatus> StmtDeclaration<S> { | |||
|         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<S: ModuleBuildingStatus> StmtDeclaration<S> { | |||
|         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((<S: ModuleBuildingStatus>) Stmt<S>)] | ||||
|     #[derive(Clone, PartialEq, Eq, Hash)] | ||||
|     pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> { | ||||
|         #[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<S>), | ||||
|         #[is = is_match, as_ref = match_] | ||||
|         #[is = is_match, as_ref = match_, from = from] | ||||
|         Match(StmtMatch<S>), | ||||
|         #[is = is_declaration, as_ref = declaration] | ||||
|         #[is = is_declaration, as_ref = declaration, from = from] | ||||
|         Declaration(StmtDeclaration<S>), | ||||
|     } | ||||
| } | ||||
|  | @ -982,6 +1026,14 @@ impl From<NormalModuleBody<ModuleBuilding>> 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<CD> RegBuilder<CD, (), ()> { | |||
| } | ||||
| 
 | ||||
| impl<I, T: Type> RegBuilder<(), I, T> { | ||||
|     pub fn clock_domain( | ||||
|     pub fn clock_domain<R: ResetType>( | ||||
|         self, | ||||
|         clock_domain: impl ToExpr<Type = ClockDomain>, | ||||
|     ) -> RegBuilder<Expr<ClockDomain>, I, T> { | ||||
|         clock_domain: impl ToExpr<Type = ClockDomain<R>>, | ||||
|     ) -> RegBuilder<Expr<ClockDomain<R>>, I, T> { | ||||
|         let Self { | ||||
|             name, | ||||
|             source_location, | ||||
|  | @ -1887,7 +1947,7 @@ impl<I, T: Type> RegBuilder<(), I, T> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> RegBuilder<Expr<ClockDomain>, Option<Expr<T>>, T> { | ||||
| impl<T: Type, R: ResetType> RegBuilder<Expr<ClockDomain<R>>, Option<Expr<T>>, T> { | ||||
|     #[track_caller] | ||||
|     pub fn build(self) -> Expr<T> { | ||||
|         let Self { | ||||
|  | @ -2212,6 +2272,16 @@ pub fn annotate<T: Type>(target: Expr<T>, 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<T: Type> { | ||||
|     pub instantiated_module: InstantiatedModule, | ||||
|     pub target: Expr<T>, | ||||
|     pub expr: Expr<T>, | ||||
| } | ||||
|  |  | |||
|  | @ -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), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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<T: Type> { | ||||
| pub struct Reg<T: Type, R: ResetType = Reset> { | ||||
|     name: ScopedNameId, | ||||
|     source_location: SourceLocation, | ||||
|     ty: T, | ||||
|     clock_domain: Expr<ClockDomain>, | ||||
|     clock_domain: Expr<ClockDomain<R>>, | ||||
|     init: Option<Expr<T>>, | ||||
| } | ||||
| 
 | ||||
| impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> { | ||||
| impl<T: Type + fmt::Debug, R: ResetType> fmt::Debug for Reg<T, R> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let Self { | ||||
|             name, | ||||
|  | @ -37,8 +38,8 @@ impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> Reg<T> { | ||||
|     pub fn canonical(&self) -> Reg<CanonicalType> { | ||||
| impl<T: Type, R: ResetType> Reg<T, R> { | ||||
|     pub fn canonical(&self) -> Reg<CanonicalType, R> { | ||||
|         let Self { | ||||
|             name, | ||||
|             source_location, | ||||
|  | @ -59,7 +60,7 @@ impl<T: Type> Reg<T> { | |||
|         scoped_name: ScopedNameId, | ||||
|         source_location: SourceLocation, | ||||
|         ty: T, | ||||
|         clock_domain: Expr<ClockDomain>, | ||||
|         clock_domain: Expr<ClockDomain<R>>, | ||||
|         init: Option<Expr<T>>, | ||||
|     ) -> Self { | ||||
|         assert!( | ||||
|  | @ -98,7 +99,7 @@ impl<T: Type> Reg<T> { | |||
|     pub fn scoped_name(&self) -> ScopedNameId { | ||||
|         self.name | ||||
|     } | ||||
|     pub fn clock_domain(&self) -> Expr<ClockDomain> { | ||||
|     pub fn clock_domain(&self) -> Expr<ClockDomain<R>> { | ||||
|         self.clock_domain | ||||
|     } | ||||
|     pub fn init(&self) -> Option<Expr<T>> { | ||||
|  |  | |||
|  | @ -11,10 +11,21 @@ mod sealed { | |||
|     pub trait ResetTypeSealed {} | ||||
| } | ||||
| 
 | ||||
| pub trait ResetType: StaticType<MaskType = Bool> + sealed::ResetTypeSealed {} | ||||
| pub trait ResetType: StaticType<MaskType = Bool> + sealed::ResetTypeSealed { | ||||
|     fn dispatch<D: ResetTypeDispatch>(input: D::Input<Self>, dispatch: D) -> D::Output<Self>; | ||||
| } | ||||
| 
 | ||||
| pub trait ResetTypeDispatch: Sized { | ||||
|     type Input<T: ResetType>; | ||||
|     type Output<T: ResetType>; | ||||
| 
 | ||||
|     fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset>; | ||||
|     fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset>; | ||||
|     fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset>; | ||||
| } | ||||
| 
 | ||||
| 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<D: ResetTypeDispatch>( | ||||
|                 input: D::Input<Self>, | ||||
|                 dispatch: D, | ||||
|             ) -> D::Output<Self> { | ||||
|                 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 { | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -1047,9 +1047,9 @@ | |||
|                 "clock_domain()": "Visible", | ||||
|                 "init()": "Visible" | ||||
|             }, | ||||
|             "generics": "<T: Type>", | ||||
|             "fold_where": "T: Fold<State>", | ||||
|             "visit_where": "T: Visit<State>" | ||||
|             "generics": "<T: Type, R: ResetType>", | ||||
|             "fold_where": "T: Fold<State>, R: Fold<State>", | ||||
|             "visit_where": "T: Visit<State>, R: Visit<State>" | ||||
|         }, | ||||
|         "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": "<R: ResetType>", | ||||
|             "fold_where": "R: Fold<State>", | ||||
|             "visit_where": "R: Visit<State>" | ||||
|         }, | ||||
|         "StmtWire": { | ||||
|             "data": { | ||||
|  | @ -1219,6 +1224,8 @@ | |||
|                 "ModuleIO": "Visible", | ||||
|                 "MemPort": "Visible", | ||||
|                 "Reg": "Visible", | ||||
|                 "RegSync": "Visible", | ||||
|                 "RegAsync": "Visible", | ||||
|                 "Wire": "Visible", | ||||
|                 "Instance": "Visible" | ||||
|             } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue