make ClockDomain and Reg generic over reset type
All checks were successful
/ deps (push) Successful in 15s
/ test (push) Successful in 4m57s
/ deps (pull_request) Successful in 13s
/ test (pull_request) Successful in 4m55s

This commit is contained in:
Jacob Lifshay 2024-11-26 20:47:03 -08:00
parent 89d84551f8
commit 9b5f1218fd
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
11 changed files with 306 additions and 85 deletions

View file

@ -4,7 +4,7 @@ use crate::{
expr::{Expr, ToExpr}, expr::{Expr, ToExpr},
hdl, hdl,
int::Bool, int::Bool,
reset::Reset, reset::{Reset, ResetType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
}; };
@ -88,9 +88,9 @@ impl ToClock for Expr<Clock> {
} }
#[hdl] #[hdl]
pub struct ClockDomain { pub struct ClockDomain<R: ResetType = Reset> {
pub clk: Clock, pub clk: Clock,
pub rst: Reset, pub rst: R,
} }
impl ToClock for bool { impl ToClock for bool {

View file

@ -17,6 +17,7 @@ use crate::{
Instance, ModuleIO, Instance, ModuleIO,
}, },
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
ty::{CanonicalType, StaticType, Type, TypeWithDeref}, ty::{CanonicalType, StaticType, Type, TypeWithDeref},
wire::Wire, wire::Wire,
}; };
@ -209,7 +210,9 @@ expr_enum! {
ModuleIO(ModuleIO<CanonicalType>), ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>), Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>), Wire(Wire<CanonicalType>),
Reg(Reg<CanonicalType>), Reg(Reg<CanonicalType, Reset>),
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>), 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; type Type = T;
fn to_expr(&self) -> Expr<Self::Type> { 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 { Expr {
__enum: ExprEnum::Reg(self.canonical()).intern_sized(), __enum: R::dispatch(self.canonical(), Dispatch).intern_sized(),
__ty: self.ty(), __ty: self.ty(),
__flow: self.flow(), __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> { fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(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>> { fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into())) Some(Intern::intern_sized(self.canonical().into()))
} }

View file

@ -8,6 +8,7 @@ use crate::{
memory::{DynPortType, MemPort}, memory::{DynPortType, MemPort},
module::{Instance, ModuleIO, TargetName}, module::{Instance, ModuleIO, TargetName},
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
wire::Wire, wire::Wire,
@ -127,6 +128,7 @@ macro_rules! impl_target_base {
$(#[$enum_meta:meta])* $(#[$enum_meta:meta])*
$enum_vis:vis enum $TargetBase:ident { $enum_vis:vis enum $TargetBase:ident {
$( $(
$(#[from = $from:ident])?
#[is = $is_fn:ident] #[is = $is_fn:ident]
#[to = $to_fn:ident] #[to = $to_fn:ident]
$(#[$variant_meta:meta])* $(#[$variant_meta:meta])*
@ -150,19 +152,19 @@ macro_rules! impl_target_base {
} }
} }
$( $($(
impl From<$VariantTy> for $TargetBase { impl From<$VariantTy> for $TargetBase {
fn from(value: $VariantTy) -> Self { fn $from(value: $VariantTy) -> Self {
Self::$Variant(value) Self::$Variant(value)
} }
} }
impl From<$VariantTy> for Target { impl From<$VariantTy> for Target {
fn from(value: $VariantTy) -> Self { fn $from(value: $VariantTy) -> Self {
$TargetBase::$Variant(value).into() $TargetBase::$Variant(value).into()
} }
} }
)* )*)?
impl $TargetBase { impl $TargetBase {
$( $(
@ -199,24 +201,63 @@ macro_rules! impl_target_base {
impl_target_base! { impl_target_base! {
#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum TargetBase { pub enum TargetBase {
#[from = from]
#[is = is_module_io] #[is = is_module_io]
#[to = module_io] #[to = module_io]
ModuleIO(ModuleIO<CanonicalType>), ModuleIO(ModuleIO<CanonicalType>),
#[from = from]
#[is = is_mem_port] #[is = is_mem_port]
#[to = mem_port] #[to = mem_port]
MemPort(MemPort<DynPortType>), MemPort(MemPort<DynPortType>),
#[is = is_reg] #[is = is_reg]
#[to = 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] #[is = is_wire]
#[to = wire] #[to = wire]
Wire(Wire<CanonicalType>), Wire(Wire<CanonicalType>),
#[from = from]
#[is = is_instance] #[is = is_instance]
#[to = instance] #[to = instance]
Instance(Instance<Bundle>), 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 { impl fmt::Display for TargetBase {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.target_name()) write!(f, "{:?}", self.target_name())
@ -229,6 +270,8 @@ impl TargetBase {
TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None), TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None),
TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())), TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())),
TargetBase::Reg(v) => TargetName(v.scoped_name(), None), 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::Wire(v) => TargetName(v.scoped_name(), None),
TargetBase::Instance(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::ModuleIO(v) => v.ty(),
TargetBase::MemPort(v) => v.ty().canonical(), TargetBase::MemPort(v) => v.ty().canonical(),
TargetBase::Reg(v) => v.ty(), TargetBase::Reg(v) => v.ty(),
TargetBase::RegSync(v) => v.ty(),
TargetBase::RegAsync(v) => v.ty(),
TargetBase::Wire(v) => v.ty(), TargetBase::Wire(v) => v.ty(),
TargetBase::Instance(v) => v.ty().canonical(), TargetBase::Instance(v) => v.ty().canonical(),
} }

View file

@ -31,7 +31,7 @@ use crate::{
StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg,
StmtWire, StmtWire,
}, },
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, ResetType, SyncReset},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
util::{ util::{
@ -1739,6 +1739,14 @@ impl<'a> Exporter<'a> {
assert!(!const_ty, "not a constant"); assert!(!const_ty, "not a constant");
self.module.ns.get(expr.scoped_name().1).to_string() 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) => { ExprEnum::MemPort(expr) => {
assert!(!const_ty, "not a constant"); assert!(!const_ty, "not a constant");
let mem_name = self.module.ns.get(expr.mem_name().1); 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) self.module.ns.get(v.mem_name().1)
} }
TargetBase::Reg(v) => self.module.ns.get(v.name_id()), 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::Wire(v) => self.module.ns.get(v.name_id()),
TargetBase::Instance(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); drop(memory_indent);
Ok(body) 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( fn block(
&mut self, &mut self,
module: Interned<Module<Bundle>>, module: Interned<Module<Bundle>>,
@ -2126,30 +2167,14 @@ impl<'a> Exporter<'a> {
) )
.unwrap(); .unwrap();
} }
Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations, reg })) => { Stmt::Declaration(StmtDeclaration::Reg(stmt_reg)) => {
self.targeted_annotations(module_name, vec![], &annotations); self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
let name = self.module.ns.get(reg.name_id()); }
let ty = self.type_state.ty(reg.ty()); Stmt::Declaration(StmtDeclaration::RegSync(stmt_reg)) => {
let clk = self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
self.expr(Expr::canonical(reg.clock_domain().clk), &definitions, false); }
if let Some(init) = reg.init() { Stmt::Declaration(StmtDeclaration::RegAsync(stmt_reg)) => {
let rst = self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
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::Instance(StmtInstance { Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
annotations, annotations,

View file

@ -20,6 +20,7 @@ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
util::ScopedRef, util::ScopedRef,
@ -350,7 +351,7 @@ macro_rules! wrapper_enum {
$(#[$enum_meta:meta])* $(#[$enum_meta:meta])*
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $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_meta:meta])*
$Variant:ident($VariantTy:ty), $Variant:ident($VariantTy:ty),
)* )*
@ -362,7 +363,7 @@ macro_rules! wrapper_enum {
$(#[$enum_meta])* $(#[$enum_meta])*
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $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_meta])*
$Variant($VariantTy), $Variant($VariantTy),
)* )*
@ -389,7 +390,7 @@ macro_rules! wrapper_enum {
$(#[$enum_meta:meta])* $(#[$enum_meta:meta])*
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $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_meta:meta])*
$Variant:ident($VariantTy:ty), $Variant:ident($VariantTy:ty),
)* )*
@ -401,22 +402,22 @@ macro_rules! wrapper_enum {
$(#[$enum_meta])* $(#[$enum_meta])*
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $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_meta])*
$Variant($VariantTy), $Variant($VariantTy),
)* )*
} }
} }
$( $($(
wrapper_enum! { wrapper_enum! {
impl $T_to From<$VariantTy> for $to_type { impl $T_to From<$VariantTy> for $to_type {
fn from(value: $VariantTy) -> Self { fn $from(value: $VariantTy) -> Self {
$enum_name::$Variant(value).into() $enum_name::$Variant(value).into()
} }
} }
} }
)* )?)*
}; };
( (
#[impl()] #[impl()]
@ -424,7 +425,7 @@ macro_rules! wrapper_enum {
$(#[$enum_meta:meta])* $(#[$enum_meta:meta])*
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $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_meta:meta])*
$Variant:ident($VariantTy:ty), $Variant:ident($VariantTy:ty),
)* )*
@ -466,12 +467,12 @@ pub struct StmtWire<S: ModuleBuildingStatus = ModuleBuilt> {
impl Copy for StmtWire {} impl Copy for StmtWire {}
#[derive(Hash, Clone, PartialEq, Eq, Debug)] #[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 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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> { pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> {
@ -489,22 +490,57 @@ wrapper_enum! {
#[to((<S: ModuleBuildingStatus>) StmtDeclaration<S>, (<S: ModuleBuildingStatus>) Stmt<S>)] #[to((<S: ModuleBuildingStatus>) StmtDeclaration<S>, (<S: ModuleBuildingStatus>) Stmt<S>)]
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum StmtDeclaration<S: ModuleBuildingStatus = ModuleBuilt> { pub enum StmtDeclaration<S: ModuleBuildingStatus = ModuleBuilt> {
#[is = is_wire, as_ref = wire] #[is = is_wire, as_ref = wire, from = from]
Wire(StmtWire<S>), Wire(StmtWire<S>),
#[is = is_reg, as_ref = reg] #[is = is_reg, as_ref = reg]
Reg(StmtReg<S>), Reg(StmtReg<Reset, S>),
#[is = is_instance, as_ref = instance] #[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>), Instance(StmtInstance<S>),
} }
} }
impl Copy for StmtDeclaration {} 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> { impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
pub fn annotations(&self) -> S::StmtAnnotations { pub fn annotations(&self) -> S::StmtAnnotations {
match self { match self {
StmtDeclaration::Wire(v) => v.annotations, StmtDeclaration::Wire(v) => v.annotations,
StmtDeclaration::Reg(v) => v.annotations, StmtDeclaration::Reg(v) => v.annotations,
StmtDeclaration::RegSync(v) => v.annotations,
StmtDeclaration::RegAsync(v) => v.annotations,
StmtDeclaration::Instance(v) => v.annotations, StmtDeclaration::Instance(v) => v.annotations,
} }
} }
@ -512,6 +548,8 @@ impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
match self { match self {
StmtDeclaration::Wire(v) => v.wire.source_location(), StmtDeclaration::Wire(v) => v.wire.source_location(),
StmtDeclaration::Reg(v) => v.reg.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(), StmtDeclaration::Instance(v) => v.instance.source_location(),
} }
} }
@ -519,20 +557,26 @@ impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
match self { match self {
StmtDeclaration::Wire(v) => v.wire.scoped_name(), StmtDeclaration::Wire(v) => v.wire.scoped_name(),
StmtDeclaration::Reg(v) => v.reg.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(), StmtDeclaration::Instance(v) => v.instance.scoped_name(),
} }
} }
pub fn sub_stmt_blocks(&self) -> &[S::Block] { pub fn sub_stmt_blocks(&self) -> &[S::Block] {
match self { match self {
StmtDeclaration::Wire(_) | StmtDeclaration::Reg(_) | StmtDeclaration::Instance(_) => { StmtDeclaration::Wire(_)
&[] | StmtDeclaration::Reg(_)
} | StmtDeclaration::RegSync(_)
| StmtDeclaration::RegAsync(_)
| StmtDeclaration::Instance(_) => &[],
} }
} }
pub fn canonical_ty(&self) -> CanonicalType { pub fn canonical_ty(&self) -> CanonicalType {
match self { match self {
StmtDeclaration::Wire(v) => v.wire.ty(), StmtDeclaration::Wire(v) => v.wire.ty(),
StmtDeclaration::Reg(v) => v.reg.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()), StmtDeclaration::Instance(v) => CanonicalType::Bundle(v.instance.ty()),
} }
} }
@ -543,15 +587,15 @@ wrapper_enum! {
#[to((<S: ModuleBuildingStatus>) Stmt<S>)] #[to((<S: ModuleBuildingStatus>) Stmt<S>)]
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> { pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
#[is = is_connect, as_ref = connect] #[is = is_connect, as_ref = connect, from = from]
Connect(StmtConnect), Connect(StmtConnect),
#[is = is_formal, as_ref = formal] #[is = is_formal, as_ref = formal, from = from]
Formal(StmtFormal), Formal(StmtFormal),
#[is = is_if, as_ref = if_] #[is = is_if, as_ref = if_, from = from]
If(StmtIf<S>), If(StmtIf<S>),
#[is = is_match, as_ref = match_] #[is = is_match, as_ref = match_, from = from]
Match(StmtMatch<S>), Match(StmtMatch<S>),
#[is = is_declaration, as_ref = declaration] #[is = is_declaration, as_ref = declaration, from = from]
Declaration(StmtDeclaration<S>), Declaration(StmtDeclaration<S>),
} }
} }
@ -982,6 +1026,14 @@ impl From<NormalModuleBody<ModuleBuilding>> for NormalModuleBody {
annotations: (), annotations: (),
reg, reg,
}) => StmtReg { annotations, reg }.into(), }) => 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 { StmtDeclaration::Instance(StmtInstance {
annotations: (), annotations: (),
instance, instance,
@ -1685,6 +1737,14 @@ impl AssertValidityState {
annotations: _, annotations: _,
reg, reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), })) => 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 { Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
annotations: _, annotations: _,
instance, instance,
@ -1866,10 +1926,10 @@ impl<CD> RegBuilder<CD, (), ()> {
} }
impl<I, T: Type> RegBuilder<(), I, T> { impl<I, T: Type> RegBuilder<(), I, T> {
pub fn clock_domain( pub fn clock_domain<R: ResetType>(
self, self,
clock_domain: impl ToExpr<Type = ClockDomain>, clock_domain: impl ToExpr<Type = ClockDomain<R>>,
) -> RegBuilder<Expr<ClockDomain>, I, T> { ) -> RegBuilder<Expr<ClockDomain<R>>, I, T> {
let Self { let Self {
name, name,
source_location, 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] #[track_caller]
pub fn build(self) -> Expr<T> { pub fn build(self) -> Expr<T> {
let Self { let Self {
@ -2212,6 +2272,16 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
reg, reg,
} }
.into(), .into(),
TargetBase::RegSync(reg) => StmtReg {
annotations: (),
reg,
}
.into(),
TargetBase::RegAsync(reg) => StmtReg {
annotations: (),
reg,
}
.into(),
TargetBase::Wire(wire) => StmtWire { TargetBase::Wire(wire) => StmtWire {
annotations: (), annotations: (),
wire, wire,
@ -2698,5 +2768,5 @@ pub struct TargetInInstantiatedModule {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct ExprInInstantiatedModule<T: Type> { pub struct ExprInInstantiatedModule<T: Type> {
pub instantiated_module: InstantiatedModule, pub instantiated_module: InstantiatedModule,
pub target: Expr<T>, pub expr: Expr<T>,
} }

View file

@ -764,7 +764,9 @@ impl Folder for State {
| ExprEnum::ModuleIO(_) | ExprEnum::ModuleIO(_)
| ExprEnum::Instance(_) | ExprEnum::Instance(_)
| ExprEnum::Wire(_) | ExprEnum::Wire(_)
| ExprEnum::Reg(_) => op.default_fold(self), | ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| ExprEnum::RegAsync(_) => op.default_fold(self),
} }
} }

View file

@ -29,7 +29,7 @@ use crate::{
StmtInstance, StmtMatch, StmtReg, StmtWire, StmtInstance, StmtMatch, StmtReg, StmtWire,
}, },
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, ResetType, SyncReset},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
wire::Wire, wire::Wire,

View file

@ -5,21 +5,22 @@ use crate::{
expr::{Expr, Flow}, expr::{Expr, Flow},
intern::Interned, intern::Interned,
module::{NameId, ScopedNameId}, module::{NameId, ScopedNameId},
reset::{Reset, ResetType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
}; };
use std::fmt; use std::fmt;
#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Reg<T: Type> { pub struct Reg<T: Type, R: ResetType = Reset> {
name: ScopedNameId, name: ScopedNameId,
source_location: SourceLocation, source_location: SourceLocation,
ty: T, ty: T,
clock_domain: Expr<ClockDomain>, clock_domain: Expr<ClockDomain<R>>,
init: Option<Expr<T>>, 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { let Self {
name, name,
@ -37,8 +38,8 @@ impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
} }
} }
impl<T: Type> Reg<T> { impl<T: Type, R: ResetType> Reg<T, R> {
pub fn canonical(&self) -> Reg<CanonicalType> { pub fn canonical(&self) -> Reg<CanonicalType, R> {
let Self { let Self {
name, name,
source_location, source_location,
@ -59,7 +60,7 @@ impl<T: Type> Reg<T> {
scoped_name: ScopedNameId, scoped_name: ScopedNameId,
source_location: SourceLocation, source_location: SourceLocation,
ty: T, ty: T,
clock_domain: Expr<ClockDomain>, clock_domain: Expr<ClockDomain<R>>,
init: Option<Expr<T>>, init: Option<Expr<T>>,
) -> Self { ) -> Self {
assert!( assert!(
@ -98,7 +99,7 @@ impl<T: Type> Reg<T> {
pub fn scoped_name(&self) -> ScopedNameId { pub fn scoped_name(&self) -> ScopedNameId {
self.name self.name
} }
pub fn clock_domain(&self) -> Expr<ClockDomain> { pub fn clock_domain(&self) -> Expr<ClockDomain<R>> {
self.clock_domain self.clock_domain
} }
pub fn init(&self) -> Option<Expr<T>> { pub fn init(&self) -> Option<Expr<T>> {

View file

@ -11,10 +11,21 @@ mod sealed {
pub trait ResetTypeSealed {} 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 { 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)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct $name; pub struct $name;
@ -67,7 +78,14 @@ macro_rules! reset_type {
impl sealed::ResetTypeSealed for $name {} 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 { pub trait $Trait {
fn $trait_fn(&self) -> Expr<$name>; fn $trait_fn(&self) -> Expr<$name>;
@ -99,12 +117,13 @@ macro_rules! reset_type {
}; };
} }
reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true); reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true, async_reset);
reset_type!(SyncReset, ToSyncReset::to_sync_reset, true); reset_type!(SyncReset, ToSyncReset::to_sync_reset, true, sync_reset);
reset_type!( reset_type!(
Reset, Reset,
ToReset::to_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 { impl ToSyncReset for bool {

View file

@ -1405,6 +1405,18 @@ impl Compiler {
ty: reg.ty(), ty: reg.ty(),
} }
.into(), .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 { TargetBase::Wire(wire) => TraceWire {
name: wire.name(), name: wire.name(),
child: self.make_trace_decl_child(target, wire.name()).intern(), child: self.make_trace_decl_child(target, wire.name()).intern(),
@ -1452,7 +1464,7 @@ impl Compiler {
| TargetBase::MemPort(_) | TargetBase::MemPort(_)
| TargetBase::Wire(_) | TargetBase::Wire(_)
| TargetBase::Instance(_) => None, | TargetBase::Instance(_) => None,
TargetBase::Reg(_) => { TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => {
let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!(
"{:?}.{:?}$next", "{:?}.{:?}$next",
target.instantiated_module, target.instantiated_module,
@ -2412,6 +2424,18 @@ impl Compiler {
target: expr.into(), target: expr.into(),
}) })
.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 ExprEnum::MemPort(expr) => self
.compile_value(TargetInInstantiatedModule { .compile_value(TargetInInstantiatedModule {
instantiated_module, instantiated_module,
@ -2606,6 +2630,8 @@ impl Compiler {
let target_base: TargetBase = match &declaration { let target_base: TargetBase = match &declaration {
StmtDeclaration::Wire(v) => v.wire.into(), StmtDeclaration::Wire(v) => v.wire.into(),
StmtDeclaration::Reg(v) => v.reg.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(), StmtDeclaration::Instance(v) => v.instance.into(),
}; };
let target = TargetInInstantiatedModule { let target = TargetInInstantiatedModule {
@ -2619,6 +2645,12 @@ impl Compiler {
StmtDeclaration::Reg(StmtReg { annotations, reg }) => { StmtDeclaration::Reg(StmtReg { annotations, reg }) => {
todo!(); todo!();
} }
StmtDeclaration::RegSync(StmtReg { annotations, reg }) => {
todo!();
}
StmtDeclaration::RegAsync(StmtReg { annotations, reg }) => {
todo!();
}
StmtDeclaration::Instance(StmtInstance { StmtDeclaration::Instance(StmtInstance {
annotations, annotations,
instance, instance,

View file

@ -1047,9 +1047,9 @@
"clock_domain()": "Visible", "clock_domain()": "Visible",
"init()": "Visible" "init()": "Visible"
}, },
"generics": "<T: Type>", "generics": "<T: Type, R: ResetType>",
"fold_where": "T: Fold<State>", "fold_where": "T: Fold<State>, R: Fold<State>",
"visit_where": "T: Visit<State>" "visit_where": "T: Visit<State>, R: Visit<State>"
}, },
"Wire": { "Wire": {
"data": { "data": {
@ -1078,6 +1078,8 @@
"$kind": "Enum", "$kind": "Enum",
"Wire": "Visible", "Wire": "Visible",
"Reg": "Visible", "Reg": "Visible",
"RegSync": "Visible",
"RegAsync": "Visible",
"Instance": "Visible" "Instance": "Visible"
} }
}, },
@ -1136,7 +1138,10 @@
"$kind": "Struct", "$kind": "Struct",
"annotations": "Visible", "annotations": "Visible",
"reg": "Visible" "reg": "Visible"
} },
"generics": "<R: ResetType>",
"fold_where": "R: Fold<State>",
"visit_where": "R: Visit<State>"
}, },
"StmtWire": { "StmtWire": {
"data": { "data": {
@ -1219,6 +1224,8 @@
"ModuleIO": "Visible", "ModuleIO": "Visible",
"MemPort": "Visible", "MemPort": "Visible",
"Reg": "Visible", "Reg": "Visible",
"RegSync": "Visible",
"RegAsync": "Visible",
"Wire": "Visible", "Wire": "Visible",
"Instance": "Visible" "Instance": "Visible"
} }