make ClockDomain and Reg generic over reset type
This commit is contained in:
parent
89d84551f8
commit
9b5f1218fd
|
@ -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…
Reference in a new issue