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},
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 {

View file

@ -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()))
}

View file

@ -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(),
}

View file

@ -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,

View file

@ -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>,
}

View file

@ -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),
}
}

View file

@ -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,

View file

@ -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>> {

View file

@ -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 {

View file

@ -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,

View file

@ -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"
}