1
0
Fork 0

Compare commits

...

10 commits

Author SHA1 Message Date
80a11ec1c2
fayalite::expr::ops: add and automatically generate ops::StructuralEq 2026-06-09 00:12:03 -07:00
ffca1a279d
switch ready_valid::queue formal proofs to use formal_global_clock 2026-06-05 00:56:24 -07:00
d4d9706798
reimplement fayalite::formal and add support to the simulator
Add support to the simulator for running hdl asserts/assumes and being
able to write to the formal global clock/reset and all any/all_const/seq that are used.
This allows you to use the exact same HDL code for running a simulation and for running a formal proof.
2026-06-05 00:56:24 -07:00
5d68885eaf
fayalite::testing: add checked_vcd_output!() 2026-06-05 00:35:19 -07:00
31353862ce
fayalite/src/module: check that expressions are visible where they are used, e.g. erroring when a wire is inside an if but used outside. 2026-06-01 23:10:43 -07:00
b1116c4a1a
simplify_enums: cache folded expressions 2026-06-01 21:45:37 -07:00
6902aea3a6
firrtl: don't generate as many duplicate wires when compiling expressions 2026-06-01 20:53:22 -07:00
1880ed682f
speed up TraceAsString by caching the canonical type for can_substitute_type 2026-06-01 20:41:14 -07:00
cf3e6cfc6b
Add .to_trace_as_string() and clean up code 2026-05-14 22:13:31 -07:00
ea183eac87
add TraceAsString<T> -- sim traces it as a string rather than all its internal fields 2026-05-13 19:43:50 -07:00
93 changed files with 11618 additions and 1661 deletions

View file

@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle {
let mut fields_expr_ne = vec![];
let mut fields_valueless_eq = vec![];
let mut fields_valueless_ne = vec![];
let mut fields_structural_eq = vec![];
for field in fields.named() {
let field_ident = field.ident();
let field_ty = field.ty();
@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle {
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::STRUCTURAL_EQ
});
fields_value_eq.push(quote_spanned! {span=>
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#field_ident,
@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle {
let expr_ne_body;
let valueless_eq_body;
let valueless_ne_body;
let structural_eq;
if fields_len == 0 {
value_eq_body = quote_spanned! {span=>
true
@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle {
valueless_ne_body = quote_spanned! {span=>
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
};
structural_eq = quote_spanned! {span=>
true
};
} else {
value_eq_body = quote_spanned! {span=>
#(#fields_value_eq)&*
@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle {
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
#(#fields_valueless_ne)|*
};
structural_eq = quote_spanned! {span=>
#(#fields_structural_eq)&&*
};
};
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
@ -1261,6 +1274,14 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::STRUCTURAL_EQ {
return ::fayalite::expr::ToExpr::to_expr(
&::fayalite::expr::ops::StructuralEq::new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
),
);
}
#expr_eq_body
}
@ -1269,6 +1290,14 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::STRUCTURAL_EQ {
return !::fayalite::expr::ToExpr::to_expr(
&::fayalite::expr::ops::StructuralEq::new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
),
);
}
#expr_ne_body
}

View file

@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum {
#where_clause
{
#[allow(non_snake_case, dead_code)]
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
#vis fn #ident(
#self_token,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(
#self_token.#sim_builder_ty_field_ident,
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
@ -929,8 +931,14 @@ impl ToTokens for ParsedEnum {
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
self,
f,
)
}
}
}.to_tokens(tokens);
@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum {
let mut variants_value_eq = vec![];
let mut variants_expr_eq = vec![];
let mut fields_valueless_eq = vec![];
let mut structural_eq: Option<TokenStream> = None;
for (
variant_index,
ParsedVariant {
@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum {
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
match &mut structural_eq {
Some(structural_eq) => {
structural_eq.extend(quote_spanned! {cmp_eq.span=>
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::STRUCTURAL_EQ
});
}
None => {
structural_eq = Some(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::STRUCTURAL_EQ
});
}
}
variants_value_eq.push(quote_spanned! {span=>
(#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => {
(
#sim_value_ident::#variant_ident(__lhs_field, _),
#sim_value_ident::#variant_ident(__rhs_field, _),
) => {
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#variant_ident,
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum {
else {
::fayalite::__std::unreachable!();
};
::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs));
::fayalite::module::connect(
__retval,
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
);
}
});
fields_valueless_eq.push(quote_spanned! {span=>
@ -1043,7 +1070,10 @@ impl ToTokens for ParsedEnum {
}
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
variants_value_eq.push(quote_spanned! {span=>
(#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => {
(
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
) => {
__lhs_unknown == __rhs_unknown
}
});
@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum {
}
};
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
let structural_eq = structural_eq.unwrap_or_else(|| {
quote_spanned! {span=>
true
}
});
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
__rhs: Self,
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
) -> ::fayalite::__std::primitive::bool {
match (&*__lhs_value, &*__rhs_value) {
#(#variants_value_eq)*
@ -1083,7 +1122,18 @@ impl ToTokens for ParsedEnum {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool);
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::STRUCTURAL_EQ {
return ::fayalite::expr::ToExpr::to_expr(
&::fayalite::expr::ops::StructuralEq::new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
),
);
}
let __retval = ::fayalite::module::wire(
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
::fayalite::int::Bool,
);
::fayalite::module::connect(__retval, false);
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
#(#variants_expr_eq)*
@ -1112,7 +1162,8 @@ impl ToTokens for ParsedEnum {
type SimValue = #sim_value_ident #type_generics;
type MatchVariant = #match_variant_ident #type_generics;
type MatchActiveScope = ::fayalite::module::Scope;
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantAndInactiveScope =
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
fn match_variants(
@ -1125,7 +1176,9 @@ impl ToTokens for ParsedEnum {
::fayalite::int::Bool
}
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
::fayalite::enum_::EnumType::variants(#self_token),
))
}
#[track_caller]
#[allow(non_snake_case)]
@ -1134,7 +1187,11 @@ impl ToTokens for ParsedEnum {
::fayalite::__std::panic!("expected enum");
};
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
::fayalite::__std::assert_eq!(
#variants_token.len(),
#variants_len,
"enum has wrong number of variants",
);
Self {
#(#from_canonical_body_fields)*
}
@ -1180,7 +1237,10 @@ impl ToTokens for ParsedEnum {
type SimBuilder = #sim_builder_ident #type_generics;
fn match_activate_scope(
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
) -> (
<Self as ::fayalite::ty::Type>::MatchVariant,
<Self as ::fayalite::ty::Type>::MatchActiveScope,
) {
let (#variant_access_token, scope) = v.activate();
(
match #variant_access_token.variant_index() {
@ -1200,7 +1260,10 @@ impl ToTokens for ParsedEnum {
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
}
}
@ -1213,7 +1276,10 @@ impl ToTokens for ParsedEnum {
&self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
::fayalite::sim::value::SimValue::from_value(
ty,
::fayalite::__std::clone::Clone::clone(self),
)
}
fn into_sim_value_with_type(
self,

View file

@ -238,7 +238,10 @@ impl TargetedAnnotation {
}
#[track_caller]
pub fn assert_valid_target(target: Interned<Target>) {
assert!(target.is_static(), "can't annotate non-static targets");
assert!(
target.is_valid_annotation_target(),
"not a valid annotation target: {target:?}",
);
}
pub fn target(&self) -> Interned<Target> {
self.target

View file

@ -367,6 +367,8 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
where
Lhs: HdlPartialEqImpl<Rhs>,
{
const STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::STRUCTURAL_EQ;
fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,

View file

@ -708,6 +708,8 @@ macro_rules! impl_tuples {
}
}
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
const STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::STRUCTURAL_EQ)*;
#[track_caller]
fn cmp_value_eq(
lhs: Self,

View file

@ -6,6 +6,7 @@ use crate::{
bundle::{Bundle, BundleType},
enum_::{Enum, EnumType},
expr::target::{GetTarget, Target},
formal::FormalInput,
int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{DynPortType, MemPort, PortType},
@ -17,7 +18,7 @@ use crate::{
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
ty::{CanonicalType, OpaqueSimValue, StaticType, Type, TypeWithDeref},
ty::{CanonicalType, OpaqueSimValue, StaticType, TraceAsString, Type, TypeWithDeref},
util::{ConstBool, ConstUsize},
wire::Wire,
};
@ -218,6 +219,9 @@ expr_enum! {
SliceSInt(ops::SliceSInt),
CastToBits(ops::CastToBits),
CastBitsTo(ops::CastBitsTo),
ToTraceAsString(ops::ToTraceAsString),
TraceAsStringAsInner(ops::TraceAsStringAsInner),
StructuralEq(ops::StructuralEq),
ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>),
@ -225,6 +229,8 @@ expr_enum! {
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>),
FormalInput(FormalInput),
SimIoForGlobal(ops::SimIoForGlobal),
}
}
@ -389,6 +395,35 @@ impl<T: Type> Expr<T> {
__flow: this.__flow,
}
}
#[track_caller]
pub fn as_trace_as_string(this: Self, ty: TraceAsString<T>) -> Expr<TraceAsString<T>> {
assert_eq!(this.ty(), ty.inner_ty());
ops::ToTraceAsString::new(Expr::canonical(this), ty).to_expr()
}
}
impl Expr<CanonicalType> {
pub fn unwrap_transparent_types(mut this: Self) -> Expr<CanonicalType> {
loop {
match this.ty() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => return this,
CanonicalType::TraceAsString(_) => {
this = *Expr::<TraceAsString>::from_canonical(this);
}
}
}
}
}
impl<T: Type> ToLiteralBits for Expr<T> {
@ -667,6 +702,7 @@ macro_rules! impl_hdl_cmp {
impl_helper = $HdlCmpImplHelper:ident,
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
$(structural_eq = $STRUCTURAL_EQ:ident,)?
]
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
@ -695,6 +731,8 @@ macro_rules! impl_hdl_cmp {
}
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
$(const $STRUCTURAL_EQ: bool;)?
$(#[track_caller]
fn $cmp_value_fn(
$cmp_value_lhs: Self,
@ -878,6 +916,7 @@ impl_hdl_cmp! {
#[
impl_helper = HdlPartialEqImplHelper,
impl_helper_sealed = HdlPartialEqImplHelperSealed,
structural_eq = STRUCTURAL_EQ,
]
pub trait HdlPartialEq<Rhs: ValueType>:
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
@ -1692,3 +1731,204 @@ impl<'a, T: Type> ToSimValueInner<'a> for &'a SimValue<T> {
Cow::Borrowed(&**this)
}
}
pub trait ToTraceAsString: ValueType {
type Output: ValueType<Type = TraceAsString<Self::Type>, ValueCategory = Self::ValueCategory>;
fn to_trace_as_string_with_ty(&self, ty: TraceAsString<Self::Type>) -> Self::Output;
fn into_trace_as_string_with_ty(self, ty: TraceAsString<Self::Type>) -> Self::Output
where
Self: Sized;
fn to_trace_as_string(&self) -> Self::Output;
fn into_trace_as_string(self) -> Self::Output
where
Self: Sized;
}
impl<
T: ?Sized
+ ValueType
+ ToTraceAsStringImpl<<Self as ValueType>::Type, <Self as ValueType>::ValueCategory>,
> ToTraceAsString for T
{
type Output = T::ImplOutput;
fn to_trace_as_string_with_ty(&self, ty: TraceAsString<Self::Type>) -> Self::Output {
Self::to_trace_as_string_with_ty_impl(self, ty)
}
fn into_trace_as_string_with_ty(self, ty: TraceAsString<Self::Type>) -> Self::Output
where
Self: Sized,
{
Self::into_trace_as_string_with_ty_impl(self, ty)
}
fn to_trace_as_string(&self) -> Self::Output {
Self::to_trace_as_string_impl(self)
}
fn into_trace_as_string(self) -> Self::Output
where
Self: Sized,
{
Self::into_trace_as_string_impl(self)
}
}
pub trait ToTraceAsStringImpl<Ty: Type, C: value_category::ValueCategory> {
type ImplOutput: ValueType<Type = TraceAsString<Ty>, ValueCategory = C>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput;
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized;
fn to_trace_as_string_with_ty_impl(this: &Self, ty: TraceAsString<Ty>) -> Self::ImplOutput;
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<Ty>) -> Self::ImplOutput
where
Self: Sized;
}
impl<T: ?Sized + crate::sim::value::ToSimValue>
ToTraceAsStringImpl<T::Type, value_category::ValueCategoryValue> for T
{
type ImplOutput = crate::ty::TraceAsStringSimValue<T::Type>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new(this)
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new(this)
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty)
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty)
}
}
impl<T: ?Sized + crate::sim::value::ToSimValue>
ToTraceAsStringImpl<T::Type, value_category::ValueCategorySimValue> for T
{
type ImplOutput = SimValue<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new(this).into_sim_value()
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new(this).into_sim_value()
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value()
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value()
}
}
impl<T: ?Sized + ToExpr> ToTraceAsStringImpl<T::Type, value_category::ValueCategoryExpr> for T {
type ImplOutput = Expr<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
let this = this.to_expr();
ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr()
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
let this = this.to_expr();
ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr()
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
let this = this.to_expr();
ops::ToTraceAsString::new(
Expr::canonical(this),
ty.with_new_inner_ty(this.ty().intern_sized()),
)
.to_expr()
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
let this = this.to_expr();
ops::ToTraceAsString::new(
Expr::canonical(this),
ty.with_new_inner_ty(this.ty().intern_sized()),
)
.to_expr()
}
}
impl<T: ?Sized + ValueType> ToTraceAsStringImpl<T::Type, value_category::ValueCategoryValueless>
for T
{
type ImplOutput = Valueless<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
Valueless::new(TraceAsString::new(this.ty()))
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
Valueless::new(TraceAsString::new(this.ty()))
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized()))
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized()))
}
}
impl ToLiteralBits for FormalInput {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl ToExpr for FormalInput {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::FormalInput(*self).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}

View file

@ -12,22 +12,24 @@ use crate::{
ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless,
target::{
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
value_category::ValueCategoryExpr,
},
formal::FormalInput,
int::{
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
UIntType, UIntValue,
},
intern::{Intern, Interned},
intern::{Intern, Interned, MemoizeGeneric},
phantom_const::{PhantomConst, PhantomConstValue},
reset::{
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
ToSyncReset,
},
sim::value::{SimValue, ToSimValue},
ty::{CanonicalType, StaticType, Type},
ty::{CanonicalType, StaticType, TraceAsString, Type},
util::ConstUsize,
};
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
@ -44,6 +46,9 @@ use std::{
},
};
#[cfg(test)]
mod test_ops_impls;
macro_rules! make_impls {
(
$([$($args:tt)*])?
@ -583,9 +588,6 @@ macro_rules! make_impls {
#[cfg(test)]
pub(crate) use make_impls;
#[cfg(test)]
mod test_ops_impls;
macro_rules! impl_simple_binary_op_trait {
(
[$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*),
@ -2982,6 +2984,7 @@ macro_rules! impl_compare_op {
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
#[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)]
#[type($Lhs:ty, $Rhs:ty)]
$(#[structural_eq = $STRUCTURAL_EQ:ident])?
#[trait($Trait:ident)]
$(
struct $name:ident;
@ -3043,6 +3046,7 @@ macro_rules! impl_compare_op {
})*
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
$(const $STRUCTURAL_EQ: bool = true;)?
$(fn $value_method(
_lhs: Self,
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
@ -3063,6 +3067,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => lhs, rhs => rhs)]
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
#[type(Bool, Bool)]
#[structural_eq = STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3086,6 +3091,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
#[structural_eq = STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3110,6 +3116,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
#[structural_eq = STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3131,6 +3138,8 @@ impl_compare_op! {
macro_rules! impl_compare_forwards_to_bool {
($ty:ident) => {
impl HdlPartialEqImpl<Self> for $ty {
const STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -4694,3 +4703,452 @@ impl<This: ExprFromIterator<A>, A> FromIterator<A> for Expr<This> {
This::expr_from_iter(iter)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ToTraceAsString<T: Type = CanonicalType> {
inner: Expr<CanonicalType>,
ty: TraceAsString<T>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for ToTraceAsString<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
inner,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("ToTraceAsString")
.field("inner", inner)
.finish_non_exhaustive()
}
}
impl<T: Type> ToTraceAsString<T> {
pub fn new(inner: Expr<CanonicalType>, ty: TraceAsString<T>) -> Self {
assert_eq!(inner.ty(), ty.inner_ty().canonical());
let literal_bits = inner.to_literal_bits();
let target = inner.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathToTraceAsString {
ty: ty.canonical_trace_as_string(),
}
.into(),
))
.canonicalized(),
)
});
Self {
inner,
ty,
literal_bits,
target,
}
}
pub fn inner(self) -> Expr<CanonicalType> {
self.inner
}
}
impl<T: Type> GetTarget for ToTraceAsString<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for ToTraceAsString<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for ToTraceAsString<T> {
type Type = TraceAsString<T>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for ToTraceAsString<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ToTraceAsString(ToTraceAsString {
inner: self.inner,
ty: self.ty.canonical_trace_as_string(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.inner),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TraceAsStringAsInner<T: Type = CanonicalType> {
arg: Expr<TraceAsString<CanonicalType>>,
ty: T,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for TraceAsStringAsInner<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
arg,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("TraceAsStringAsInner")
.field("arg", arg)
.finish_non_exhaustive()
}
}
impl<T: Type> TraceAsStringAsInner<T> {
pub fn from_arg_and_ty(arg: Expr<TraceAsString<CanonicalType>>, ty: T) -> Self {
assert_eq!(arg.ty().inner_ty(), ty.canonical());
let literal_bits = arg.to_literal_bits();
let target = arg.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathTraceAsStringInner {}.into(),
))
.canonicalized(),
)
});
Self {
arg,
ty,
literal_bits,
target,
}
}
pub fn new(arg: Expr<TraceAsString<T>>) -> Self {
Self::from_arg_and_ty(
Expr {
__enum: arg.__enum,
__ty: arg.__ty.canonical_trace_as_string(),
__flow: arg.__flow,
},
arg.ty().inner_ty(),
)
}
pub fn arg(self) -> Expr<TraceAsString<CanonicalType>> {
self.arg
}
pub fn arg_typed(self) -> Expr<TraceAsString<T>> {
Expr {
__enum: self.arg.__enum,
__ty: TraceAsString::from_canonical_trace_as_string(self.arg.__ty),
__flow: self.arg.__flow,
}
}
}
impl<T: Type> GetTarget for TraceAsStringAsInner<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for TraceAsStringAsInner<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for TraceAsStringAsInner<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for TraceAsStringAsInner<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::TraceAsStringAsInner(TraceAsStringAsInner {
arg: self.arg,
ty: self.ty.canonical(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.arg),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
/// The [`Simulation::io()`] equivalent for a global signal, this is a flipped version of a global signal
/// that allows you to e.g. use [`Simulation::write()`] to write to [`formal_global_clock()`].
///
/// [`Simulation::io()`]: crate::sim::Simulation::io
/// [`Simulation::write()`]: crate::sim::Simulation::write
/// [`formal_global_clock()`]: crate::formal::formal_global_clock
pub struct SimIoForGlobal {
global: FormalInput,
}
impl fmt::Debug for SimIoForGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimIoForGlobal").field(&self.global).finish()
}
}
impl SimIoForGlobal {
pub fn new(global: FormalInput) -> Self {
Self { global }
}
pub fn global(self) -> FormalInput {
self.global
}
pub(crate) fn must_connect_to(self) -> bool {
true
}
pub fn flow(self) -> Flow {
self.global.flow().flip()
}
pub(crate) fn source_location(self) -> crate::source_location::SourceLocation {
self.global.source_location()
}
}
impl GetTarget for SimIoForGlobal {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::from(*self).intern_sized())
}
}
impl ToLiteralBits for SimIoForGlobal {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl ValueType for SimIoForGlobal {
type Type = CanonicalType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.global.ty()
}
}
impl ToExpr for SimIoForGlobal {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::SimIoForGlobal(*self).intern(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct StructuralEq {
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
assume_padding_is_zeroed: bool,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl StructuralEq {
fn literal_eq(
ty: CanonicalType,
l: Interned<BitSlice>,
r: Interned<BitSlice>,
) -> Result<bool, NotALiteralExpr> {
enum PairRefOrInternedBitSlice<'a> {
Ref(&'a BitSlice, &'a BitSlice),
Interned(Interned<BitSlice>, Interned<BitSlice>),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct MyMemoize(CanonicalType);
impl MemoizeGeneric for MyMemoize {
type InputRef<'a> = (&'a BitSlice, &'a BitSlice);
type InputOwned = (Interned<BitSlice>, Interned<BitSlice>);
type InputCow<'a> = PairRefOrInternedBitSlice<'a>;
type Output = Result<bool, NotALiteralExpr>;
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
a == b
}
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
let (l, r) = input;
(l, r)
}
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
match input {
PairRefOrInternedBitSlice::Ref(l, r) => (l.intern(), r.intern()),
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
}
}
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
match input {
PairRefOrInternedBitSlice::Ref(l, r) => (l, r),
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
}
}
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
let (l, r) = input;
PairRefOrInternedBitSlice::Interned(l, r)
}
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
let (l, r) = input;
PairRefOrInternedBitSlice::Ref(l, r)
}
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
let (mut l, mut r) = input;
match self.0 {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => Ok(l == r),
CanonicalType::Array(ty) => {
let element_ty = ty.element();
let element_bit_width = element_ty.bit_width();
let mut eq = true;
for element_index in 0..ty.len() {
if !Self(element_ty).get((
&l[element_bit_width * element_index..][..element_bit_width],
&r[element_bit_width * element_index..][..element_bit_width],
))? {
eq = false;
break;
}
}
Ok(eq)
}
CanonicalType::Enum(ty) => {
let discriminant_bit_width = ty.discriminant_bit_width();
let (l_discriminant_bits, l_body_bits) = l.split_at(discriminant_bit_width);
let (r_discriminant_bits, r_body_bits) = r.split_at(discriminant_bit_width);
if l_discriminant_bits != r_discriminant_bits {
return Ok(false);
}
let mut discriminant = 0usize;
discriminant.view_bits_mut::<Lsb0>()[..l_discriminant_bits.len()]
.copy_from_bitslice(l_discriminant_bits);
match ty.variants().get(discriminant) {
Some(&EnumVariant {
name: _,
ty: Some(variant_ty),
}) => {
let variant_bit_width = variant_ty.bit_width();
Self(variant_ty).get((
&l_body_bits[..variant_bit_width],
&r_body_bits[..variant_bit_width],
))
}
Some(EnumVariant { name: _, ty: None }) => Ok(true),
None => Err(NotALiteralExpr),
}
}
CanonicalType::Bundle(ty) => {
let mut eq = true;
for field in &ty.fields() {
let field_bit_width = field.ty.bit_width();
let l_field;
let r_field;
(l_field, l) = l.split_at(field_bit_width);
(r_field, r) = r.split_at(field_bit_width);
if !Self(field.ty).get((l_field, r_field))? {
eq = false;
break;
}
}
Ok(eq)
}
CanonicalType::DynSimOnly(_) => unreachable!("doesn't have literal_bits"),
CanonicalType::TraceAsString(ty) => Self(ty.inner_ty()).get((l, r)),
}
}
}
MyMemoize(ty).get_owned((l, r))
}
#[track_caller]
pub fn new(lhs: Expr<CanonicalType>, rhs: Expr<CanonicalType>) -> Self {
Self::new_unchecked(lhs, rhs, false)
}
#[track_caller]
pub fn new_unchecked(
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
assume_padding_is_zeroed: bool,
) -> Self {
let ty = lhs.ty();
assert_eq!(ty, rhs.ty());
Self {
lhs,
rhs,
assume_padding_is_zeroed,
literal_bits: lhs.to_literal_bits().and_then(|lhs| {
let rhs = rhs.to_literal_bits()?;
if assume_padding_is_zeroed {
lhs == rhs
} else {
Self::literal_eq(ty, lhs, rhs)?
}
.to_literal_bits()
}),
}
}
pub fn lhs(self) -> Expr<CanonicalType> {
self.lhs
}
pub fn rhs(self) -> Expr<CanonicalType> {
self.rhs
}
pub fn assume_padding_is_zeroed(self) -> bool {
self.assume_padding_is_zeroed
}
}
impl ToLiteralBits for StructuralEq {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] StructuralEq);
impl ValueType for StructuralEq {
type Type = Bool;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
Bool
}
}
impl ToExpr for StructuralEq {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::StructuralEq(*self).intern(),
__ty: Bool,
__flow: Flow::Source,
}
}
}

View file

@ -4,13 +4,14 @@ use crate::{
array::Array,
bundle::{Bundle, BundleField},
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
formal::FormalInput,
intern::{Intern, Interned},
memory::{DynPortType, MemPort},
module::{Instance, ModuleIO, TargetName},
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
source_location::SourceLocation,
ty::{CanonicalType, Type},
ty::{CanonicalType, TraceAsString, Type},
wire::Wire,
};
use std::fmt;
@ -46,11 +47,33 @@ impl fmt::Display for TargetPathDynArrayElement {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TargetPathTraceAsStringInner {}
impl fmt::Display for TargetPathTraceAsStringInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ".<inner>")
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TargetPathToTraceAsString {
pub ty: TraceAsString<CanonicalType>,
}
impl fmt::Display for TargetPathToTraceAsString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ".to_trace_as_string(...)")
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TargetPathElement {
BundleField(TargetPathBundleField),
ArrayElement(TargetPathArrayElement),
DynArrayElement(TargetPathDynArrayElement),
TraceAsStringInner(TargetPathTraceAsStringInner),
ToTraceAsString(TargetPathToTraceAsString),
}
impl From<TargetPathBundleField> for TargetPathElement {
@ -71,12 +94,26 @@ impl From<TargetPathDynArrayElement> for TargetPathElement {
}
}
impl From<TargetPathTraceAsStringInner> for TargetPathElement {
fn from(value: TargetPathTraceAsStringInner) -> Self {
Self::TraceAsStringInner(value)
}
}
impl From<TargetPathToTraceAsString> for TargetPathElement {
fn from(value: TargetPathToTraceAsString) -> Self {
Self::ToTraceAsString(value)
}
}
impl fmt::Display for TargetPathElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BundleField(v) => v.fmt(f),
Self::ArrayElement(v) => v.fmt(f),
Self::DynArrayElement(v) => v.fmt(f),
Self::TraceAsStringInner(v) => v.fmt(f),
Self::ToTraceAsString(v) => v.fmt(f),
}
}
}
@ -100,6 +137,15 @@ impl TargetPathElement {
let parent_ty = Array::<CanonicalType>::from_canonical(parent.canonical_ty());
parent_ty.element()
}
Self::TraceAsStringInner(_) => {
let parent_ty =
TraceAsString::<CanonicalType>::from_canonical(parent.canonical_ty());
parent_ty.inner_ty()
}
&Self::ToTraceAsString(TargetPathToTraceAsString { ty }) => {
assert_eq!(parent.canonical_ty(), ty.inner_ty());
ty.canonical()
}
}
}
pub fn flow(&self, parent: Interned<Target>) -> Flow {
@ -111,13 +157,18 @@ impl TargetPathElement {
.expect("field name is known to be a valid field of parent type");
parent.flow().flip_if(field.flipped)
}
Self::ArrayElement(_) => parent.flow(),
Self::DynArrayElement(_) => parent.flow(),
Self::ArrayElement(_)
| Self::DynArrayElement(_)
| Self::TraceAsStringInner(_)
| Self::ToTraceAsString(_) => parent.flow(),
}
}
pub fn is_static(&self) -> bool {
match self {
Self::BundleField(_) | Self::ArrayElement(_) => true,
Self::BundleField(_)
| Self::ArrayElement(_)
| Self::TraceAsStringInner(_)
| Self::ToTraceAsString(_) => true,
Self::DynArrayElement(_) => false,
}
}
@ -245,6 +296,14 @@ impl_target_base! {
#[is = is_instance]
#[to = instance]
Instance(Instance<Bundle>),
#[from = from]
#[is = is_formal_input]
#[to = formal_input]
FormalInput(FormalInput),
#[from = from]
#[is = is_sim_io_for_global]
#[to = sim_io_for_global]
SimIoForGlobal(crate::expr::ops::SimIoForGlobal),
}
}
@ -293,6 +352,8 @@ impl TargetBase {
TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None),
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
TargetBase::FormalInput(v) => TargetName(v.scoped_name(), None),
TargetBase::SimIoForGlobal(v) => TargetName(v.global().scoped_name(), None),
}
}
pub fn canonical_ty(&self) -> CanonicalType {
@ -304,6 +365,21 @@ impl TargetBase {
TargetBase::RegAsync(v) => v.ty(),
TargetBase::Wire(v) => v.ty(),
TargetBase::Instance(v) => v.ty().canonical(),
TargetBase::FormalInput(v) => v.ty(),
TargetBase::SimIoForGlobal(v) => v.ty(),
}
}
pub fn is_valid_annotation_target(&self) -> bool {
match self {
Self::ModuleIO(_) => true,
Self::MemPort(_) => true,
Self::Reg(_) => true,
Self::RegSync(_) => true,
Self::RegAsync(_) => true,
Self::Wire(_) => true,
Self::Instance(_) => true,
Self::FormalInput(_) => false,
Self::SimIoForGlobal(_) => false,
}
}
}
@ -314,6 +390,7 @@ pub struct TargetChild {
path_element: Interned<TargetPathElement>,
canonical_ty: CanonicalType,
flow: Flow,
canonicalized_if_different: Option<Interned<Target>>,
}
impl fmt::Debug for TargetChild {
@ -323,6 +400,7 @@ impl fmt::Debug for TargetChild {
path_element,
canonical_ty: _,
flow: _,
canonicalized_if_different: _,
} = self;
parent.fmt(f)?;
fmt::Display::fmt(path_element, f)
@ -336,6 +414,7 @@ impl fmt::Display for TargetChild {
path_element,
canonical_ty: _,
flow: _,
canonicalized_if_different: _,
} = self;
parent.fmt(f)?;
path_element.fmt(f)
@ -343,14 +422,69 @@ impl fmt::Display for TargetChild {
}
impl TargetChild {
pub fn new(parent: Interned<Target>, path_element: Interned<TargetPathElement>) -> Self {
fn new_helper(
parent: Interned<Target>,
path_element: Interned<TargetPathElement>,
canonicalized_if_different: Option<Interned<Target>>,
) -> Self {
Self {
parent,
path_element,
canonical_ty: path_element.canonical_ty(parent),
flow: path_element.flow(parent),
canonicalized_if_different,
}
}
fn make_canonicalized_if_different(
parent: Interned<Target>,
path_element: Interned<TargetPathElement>,
) -> Option<Interned<Target>> {
use TargetPathElement::*;
match *path_element {
BundleField(_) => {}
ArrayElement(_) => {}
DynArrayElement(_) => {}
TraceAsStringInner(_) => {
if let Some(child) = parent.canonicalized().child() {
match *child.path_element() {
BundleField(_)
| ArrayElement(_)
| DynArrayElement(_)
| TraceAsStringInner(_) => {}
ToTraceAsString(_) => return Some(child.parent()),
}
}
}
ToTraceAsString(TargetPathToTraceAsString { ty }) => {
if let Some(child) = parent.canonicalized().child() {
match *child.path_element() {
BundleField(_) | ArrayElement(_) | DynArrayElement(_)
| ToTraceAsString(_) => {}
TraceAsStringInner(_) => {
if ty.canonical() == child.parent().canonical_ty() {
return Some(child.parent());
}
}
}
}
}
}
Some(
Target::Child(Self::new_helper(
parent.canonicalized_if_different()?,
path_element,
None,
))
.intern_sized(),
)
}
pub fn new(parent: Interned<Target>, path_element: Interned<TargetPathElement>) -> Self {
Self::new_helper(
parent,
path_element,
Self::make_canonicalized_if_different(parent, path_element),
)
}
pub fn parent(self) -> Interned<Target> {
self.parent
}
@ -363,6 +497,19 @@ impl TargetChild {
pub fn flow(self) -> Flow {
self.flow
}
pub fn is_canonicalized(self) -> bool {
self.canonicalized_if_different.is_none()
}
pub fn canonicalized_if_different(self) -> Option<Interned<Target>> {
self.canonicalized_if_different
}
#[must_use]
pub fn canonicalized(self) -> Target {
match self.canonicalized_if_different {
Some(v) => *v,
None => Target::Child(self),
}
}
pub fn bundle_field(self) -> Option<BundleField> {
if let TargetPathElement::BundleField(TargetPathBundleField { name }) = *self.path_element {
let parent_ty = Bundle::from_canonical(self.parent.canonical_ty());
@ -427,6 +574,16 @@ impl Target {
}
}
}
pub fn is_valid_annotation_target(&self) -> bool {
let mut target = self;
loop {
match target {
Self::Base(target_base) => return target_base.is_valid_annotation_target(),
Self::Child(v) if !v.path_element().is_static() => return false,
Self::Child(v) => target = &v.parent,
}
}
}
#[must_use]
pub fn join(&self, path_element: Interned<TargetPathElement>) -> Self {
TargetChild::new(self.intern(), path_element).into()
@ -443,6 +600,82 @@ impl Target {
Target::Child(v) => v.canonical_ty(),
}
}
pub fn is_canonicalized(self) -> bool {
match self {
Self::Base(_) => true,
Self::Child(child) => child.is_canonicalized(),
}
}
pub fn canonicalized_if_different(self) -> Option<Interned<Self>> {
match self {
Self::Base(_) => None,
Self::Child(child) => child.canonicalized_if_different(),
}
}
#[must_use]
pub fn canonicalized(self) -> Target {
match self.canonicalized_if_different() {
Some(v) => *v,
None => self,
}
}
#[must_use]
pub fn canonicalized_interned(this: Interned<Target>) -> Interned<Target> {
this.canonicalized_if_different().unwrap_or(this)
}
#[must_use]
pub fn unwrap_transparent_types(mut self) -> Target {
loop {
self = self.canonicalized();
match self.canonical_ty() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => return self,
CanonicalType::TraceAsString(_) => {
if let Self::Child(child) = self
&& let TargetPathElement::ToTraceAsString(_) = *child.path_element()
{
self = *child.parent();
} else {
self = self.join(TargetPathElement::intern_sized(
TargetPathTraceAsStringInner {}.into(),
));
}
}
}
}
}
#[must_use]
pub fn unwrap_transparent_types_interned(this: Interned<Target>) -> Interned<Target> {
let retval = this.unwrap_transparent_types();
if retval != *this {
retval.intern_sized()
} else {
this
}
}
#[must_use]
pub fn without_trailing_transparent_path_elements(mut self) -> Target {
use TargetPathElement::*;
loop {
match self {
Self::Base(_) => return self,
Self::Child(child) => match *child.path_element() {
BundleField(_) | ArrayElement(_) | DynArrayElement(_) => return self,
TraceAsStringInner(_) | ToTraceAsString(_) => self = *child.parent(),
},
}
}
}
}
impl fmt::Display for Target {
@ -467,6 +700,18 @@ pub trait GetTarget {
fn target(&self) -> Option<Interned<Target>>;
}
impl GetTarget for Target {
fn target(&self) -> Option<Interned<Target>> {
Some(self.intern())
}
}
impl GetTarget for TargetBase {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::Base(self.intern()).intern_sized())
}
}
impl GetTarget for bool {
fn target(&self) -> Option<Interned<Target>> {
None

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,189 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
expr::target::{GetTarget, Target},
int::BoolOrIntType,
intern::{Intern, Interned, Memoize},
intern::{Intern, Interned},
module::{NameId, NameIdOrGlobal, ScopedNameId},
prelude::*,
};
use std::sync::OnceLock;
use std::{fmt, sync::OnceLock};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FormalInputKind {
FormalGlobalClock,
FormalReset,
AnyConst,
AnySeq,
AllConst,
AllSeq,
}
impl FormalInputKind {
pub fn fixed_ty(self) -> Option<CanonicalType> {
match self {
Self::FormalGlobalClock => Some(Clock.into()),
Self::FormalReset => Some(SyncReset.into()),
Self::AnyConst => None,
Self::AnySeq => None,
Self::AllConst => None,
Self::AllSeq => None,
}
}
pub fn fixed_id(self) -> Option<crate::module::Id> {
struct Cache {
formal_global_clock: crate::module::Id,
formal_reset: crate::module::Id,
}
static CACHE: OnceLock<Cache> = OnceLock::new();
let cache = || {
CACHE.get_or_init(
#[cold]
|| Cache {
formal_global_clock: crate::module::Id::new(),
formal_reset: crate::module::Id::new(),
},
)
};
match self {
Self::FormalGlobalClock => Some(cache().formal_global_clock),
Self::FormalReset => Some(cache().formal_reset),
Self::AnyConst => None,
Self::AnySeq => None,
Self::AllConst => None,
Self::AllSeq => None,
}
}
pub fn fixed_source_location(self) -> Option<SourceLocation> {
match self {
Self::FormalGlobalClock | Self::FormalReset => Some(SourceLocation::builtin()),
Self::AnyConst | Self::AnySeq | Self::AllConst | Self::AllSeq => None,
}
}
pub fn name(self) -> &'static str {
match self {
Self::FormalGlobalClock => "formal_global_clock",
Self::FormalReset => "formal_reset",
Self::AnyConst => "any_const",
Self::AnySeq => "any_seq",
Self::AllConst => "all_const",
Self::AllSeq => "all_seq",
}
}
pub fn interned_name(self) -> Interned<str> {
macro_rules! impl_interned_name {
($($variant:ident,)*) => {
match self {
$(Self::$variant => {
static CACHE: OnceLock<Interned<str>> = OnceLock::new();
*CACHE.get_or_init(|| Self::$variant.name().intern())
})*
}
};
}
impl_interned_name! {
FormalGlobalClock,
FormalReset,
AnyConst,
AnySeq,
AllConst,
AllSeq,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
struct FormalInputData {
kind: FormalInputKind,
name_id: NameId,
ty: CanonicalType,
source_location: SourceLocation,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct FormalInput(Interned<FormalInputData>);
impl fmt::Debug for FormalInput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.kind().fixed_ty().is_some() {
f.write_str(&self.name())
} else {
f.debug_tuple(&self.name()).field(&self.0.ty).finish()
}
}
}
impl FormalInput {
#[track_caller]
pub fn new(
kind: FormalInputKind,
name_id: NameId,
ty: CanonicalType,
source_location: SourceLocation,
) -> Self {
let NameId(name, id) = name_id;
assert_eq!(kind.interned_name(), name);
if let Some(fixed_ty) = kind.fixed_ty() {
assert_eq!(ty, fixed_ty);
} else {
assert!(
ty.is_castable_from_bits(),
"{name} type must be castable from bits. got:\n{ty:#?}",
);
}
if let Some(fixed_source_location) = kind.fixed_source_location() {
assert_eq!(source_location, fixed_source_location);
}
if let Some(fixed_id) = kind.fixed_id() {
assert_eq!(id, fixed_id);
}
Self(
FormalInputData {
kind,
name_id,
ty,
source_location,
}
.intern_sized(),
)
}
pub fn kind(self) -> FormalInputKind {
self.0.kind
}
pub fn name(self) -> Interned<str> {
self.0.name_id.0
}
pub fn name_id(self) -> NameId {
self.0.name_id
}
pub fn scoped_name(self) -> ScopedNameId {
ScopedNameId(NameIdOrGlobal::Global, self.name_id())
}
pub fn source_location(self) -> SourceLocation {
self.0.source_location
}
pub(crate) fn must_connect_to(self) -> bool {
false
}
pub(crate) fn flow(self) -> crate::expr::Flow {
crate::expr::Flow::Source
}
}
impl ValueType for FormalInput {
type Type = CanonicalType;
type ValueCategory = crate::expr::value_category::ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.0.ty
}
}
impl GetTarget for FormalInput {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::from(*self).intern_sized())
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum FormalKind {
@ -138,110 +316,76 @@ make_formal!(
hdl_cover
);
pub trait MakeFormalExpr: Type {}
impl<T: Type> MakeFormalExpr for T {}
#[hdl]
pub fn formal_global_clock() -> Expr<Clock> {
#[hdl_module(extern)]
fn formal_global_clock() {
#[hdl]
let clk: Clock = m.output();
m.annotate_module(BlackBoxInlineAnnotation {
path: "fayalite_formal_global_clock.v".intern(),
text: r"module __fayalite_formal_global_clock(output clk);
(* gclk *)
reg clk;
endmodule
"
.intern(),
});
m.verilog_name("__fayalite_formal_global_clock");
}
#[hdl]
let formal_global_clock = instance(formal_global_clock());
formal_global_clock.clk
static CACHE: OnceLock<Expr<Clock>> = OnceLock::new();
*CACHE.get_or_init(|| {
let kind = FormalInputKind::FormalGlobalClock;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(
kind.interned_name(),
kind.fixed_id().expect("known to have a fixed Id"),
),
Clock.into(),
kind.fixed_source_location()
.expect("known to have a fixed SourceLocation"),
)
.to_expr(),
)
})
}
#[hdl]
pub fn formal_reset() -> Expr<SyncReset> {
#[hdl_module(extern)]
fn formal_reset() {
#[hdl]
let rst: SyncReset = m.output();
m.annotate_module(BlackBoxInlineAnnotation {
path: "fayalite_formal_reset.v".intern(),
text: r"module __fayalite_formal_reset(output rst);
assign rst = $initstate;
endmodule
"
.intern(),
});
m.verilog_name("__fayalite_formal_reset");
}
static MOD: OnceLock<Interned<Module<formal_reset>>> = OnceLock::new();
#[hdl]
let formal_reset = instance(*MOD.get_or_init(formal_reset));
formal_reset.rst
static CACHE: OnceLock<Expr<SyncReset>> = OnceLock::new();
*CACHE.get_or_init(|| {
let kind = FormalInputKind::FormalReset;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(
kind.interned_name(),
kind.fixed_id().expect("known to have a fixed Id"),
),
SyncReset.into(),
kind.fixed_source_location()
.expect("known to have a fixed SourceLocation"),
)
.to_expr(),
)
})
}
macro_rules! make_any_const_fn {
($ident:ident, $verilog_attribute:literal) => {
($ident:ident, $ident_with_loc:ident, $verilog_attribute:literal, $kind:ident) => {
#[track_caller]
#[hdl]
pub fn $ident<T: BoolOrIntType>(ty: T) -> Expr<T> {
#[hdl_module(extern)]
pub(super) fn $ident<T: BoolOrIntType>(ty: T) {
#[hdl]
let out: T = m.output(ty);
let width = ty.width();
let verilog_bitslice = if width == 1 {
String::new()
} else {
format!(" [{}:0]", width - 1)
};
m.annotate_module(BlackBoxInlineAnnotation {
path: Intern::intern_owned(format!(
"fayalite_{}_{width}.v",
stringify!($ident),
)),
text: Intern::intern_owned(format!(
r"module __fayalite_{}_{width}(output{verilog_bitslice} out);
(* {} *)
reg{verilog_bitslice} out;
endmodule
",
stringify!($ident),
$verilog_attribute,
)),
});
m.verilog_name(format!("__fayalite_{}_{width}", stringify!($ident)));
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct TheMemoize<T>(T);
impl<T: BoolOrIntType> Memoize for TheMemoize<T> {
type Input = ();
type InputOwned = ();
type Output = Option<Interned<Module<$ident<T>>>>;
fn inner(self, _input: &Self::Input) -> Self::Output {
if self.0.width() == 0 {
None
} else {
Some($ident(self.0))
}
}
}
let Some(module) = TheMemoize(ty).get_owned(()) else {
return 0_hdl_u0.cast_bits_to(ty);
};
#[hdl]
let $ident = instance(module);
$ident.out
$ident_with_loc(ty, SourceLocation::caller())
}
#[track_caller]
#[hdl]
pub fn $ident_with_loc<T: BoolOrIntType>(
ty: T,
source_location: SourceLocation,
) -> Expr<T> {
let kind = FormalInputKind::$kind;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(kind.interned_name(), crate::module::Id::new()),
ty.canonical(),
source_location,
)
.to_expr(),
)
}
};
}
make_any_const_fn!(any_const, "anyconst");
make_any_const_fn!(any_seq, "anyseq");
make_any_const_fn!(all_const, "allconst");
make_any_const_fn!(all_seq, "allseq");
make_any_const_fn!(any_const, any_const_with_loc, "anyconst", AnyConst);
make_any_const_fn!(any_seq, any_seq_with_loc, "anyseq", AnySeq);
make_any_const_fn!(all_const, all_const_with_loc, "allconst", AllConst);
make_any_const_fn!(all_seq, all_seq_with_loc, "allseq", AllSeq);

View file

@ -1277,6 +1277,9 @@ macro_rules! impl_int {
pub fn bitvec_mut(&mut self) -> &mut BitVec {
Arc::make_mut(&mut self.bits)
}
pub fn arc_bitvec_mut(&mut self) -> &mut Arc<BitVec> {
&mut self.bits
}
}
};
}

View file

@ -177,6 +177,8 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
}
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
const STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type {
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
for $UIntInRangeType<LhsStart, LhsEnd>
{
const STRUCTURAL_EQ: bool = true;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
@ -657,6 +661,8 @@ macro_rules! define_uint_in_range_type {
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
for $UIntInRangeType<Start, End>
{
const STRUCTURAL_EQ: bool = false;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
@ -676,6 +682,8 @@ macro_rules! define_uint_in_range_type {
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
for UIntType<Width>
{
const STRUCTURAL_EQ: bool = false;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,

View file

@ -682,27 +682,62 @@ impl<T: ?Sized + 'static + Send + Sync + AsRef<U>, U: ?Sized> AsRef<U> for Inter
#[derive(Clone, Debug)]
pub struct InternedSliceIter<T: Clone + 'static + Send + Sync> {
slice: Interned<[T]>,
index: std::ops::Range<usize>,
iter: std::iter::Cloned<std::slice::Iter<'static, T>>,
}
impl<T: Clone + 'static + Send + Sync> Default for InternedSliceIter<T> {
fn default() -> Self {
Self {
iter: [].iter().cloned(),
}
}
}
impl<T: Clone + 'static + Send + Sync> Iterator for InternedSliceIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.index.next().map(|index| self.slice[index].clone())
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.index.size_hint()
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.iter.fold(init, f)
}
}
impl<T: Clone + 'static + Send + Sync> DoubleEndedIterator for InternedSliceIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.index
.next_back()
.map(|index| self.slice[index].clone())
self.iter.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth_back(n)
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.iter.rfold(init, f)
}
}
@ -716,8 +751,7 @@ impl<T: Clone + 'static + Send + Sync> IntoIterator for Interned<[T]> {
fn into_iter(self) -> Self::IntoIter {
InternedSliceIter {
index: 0..self.len(),
slice: self,
iter: Interned::into_inner(self).iter().cloned(),
}
}
}

View file

@ -1093,6 +1093,7 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
.to_expr(),
)),
CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())),
CanonicalType::TraceAsString(ty) => Expr::from_canonical(splat_mask(ty.inner_ty(), value)),
}
}

View file

@ -8,7 +8,7 @@ use crate::{
clock::{Clock, ClockDomain},
enum_::{Enum, EnumMatchVariantsIter, EnumType},
expr::{
Expr, Flow, ToExpr, ValueType,
Expr, ExprEnum, Flow, ToExpr, ValueType,
ops::VariantAccess,
target::{
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
@ -20,6 +20,7 @@ use crate::{
int::{Bool, DynSize, Size},
intern::{Intern, Interned},
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
module::transform::visit::{Visit, Visitor},
platform::PlatformIOBuilder,
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
@ -726,7 +727,57 @@ impl fmt::Display for NameId {
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ScopedNameId(pub NameId, pub NameId);
pub enum NameIdOrGlobal {
Global,
NameId(NameId),
}
impl NameIdOrGlobal {
pub fn name_id(self) -> Option<NameId> {
match self {
Self::Global => None,
Self::NameId(v) => Some(v),
}
}
#[track_caller]
pub fn assert_is_name_id(self) {
match self {
Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"),
Self::NameId(_) => {}
}
}
#[track_caller]
pub fn unwrap_name_id(self) -> NameId {
match self {
Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"),
Self::NameId(v) => v,
}
}
}
impl fmt::Debug for NameIdOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for NameIdOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Global => f.write_str("<<Global>>"),
Self::NameId(name_id) => fmt::Display::fmt(name_id, f),
}
}
}
impl From<NameId> for NameIdOrGlobal {
fn from(value: NameId) -> Self {
Self::NameId(value)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ScopedNameId(pub NameIdOrGlobal, pub NameId);
impl fmt::Debug for ScopedNameId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -804,7 +855,7 @@ impl<T: BundleType> Instance<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(self) -> NameId {
self.scoped_name.0
self.scoped_name.0.unwrap_name_id()
}
pub fn name(self) -> Interned<str> {
self.name_id().0
@ -821,11 +872,13 @@ impl<T: BundleType> Instance<T> {
pub fn source_location(self) -> SourceLocation {
self.source_location
}
#[track_caller]
pub fn new_unchecked(
scoped_name: ScopedNameId,
instantiated: Interned<Module<T>>,
source_location: SourceLocation,
) -> Self {
scoped_name.0.assert_is_name_id();
Self {
scoped_name,
instantiated,
@ -1111,7 +1164,10 @@ fn validate_clock_for_past<S: ModuleBuildingStatus>(
let mut target = clock_for_past;
while let Target::Child(child) = target {
match *child.path_element() {
TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {}
TargetPathElement::BundleField(_)
| TargetPathElement::ArrayElement(_)
| TargetPathElement::ToTraceAsString(_)
| TargetPathElement::TraceAsStringInner(_) => {}
TargetPathElement::DynArrayElement(_) => {
panic!(
"clock_for_past: clock must be a static target (you can't use `Expr<UInt>` array indexes):\n{clock_for_past:?}"
@ -1535,6 +1591,7 @@ impl TargetState {
}
}
fn new(target: Interned<Target>, declared_in_block: usize) -> Self {
let target = Target::unwrap_transparent_types_interned(target);
Self {
target,
inner: match target.canonical_ty() {
@ -1586,17 +1643,71 @@ impl TargetState {
declared_in_block,
written_in_blocks: RefCell::default(),
},
CanonicalType::TraceAsString(_) => {
unreachable!("handled by Target::unwrap_transparent_types_interned")
}
},
}
}
}
struct VisibleExprsStack {
buf: Vec<HashSet<ExprEnum>>,
len: usize,
}
impl VisibleExprsStack {
fn top(&mut self) -> &mut HashSet<ExprEnum> {
&mut self.buf[self.len - 1]
}
fn slice(&self) -> &[HashSet<ExprEnum>] {
&self.buf[..self.len]
}
fn contains(&self, v: &ExprEnum) -> bool {
self.slice().iter().any(|i| i.contains(v))
}
fn push_empty(&mut self) {
#[cold]
fn push_empty_cold(stack: &mut VisibleExprsStack) {
stack.buf.push(HashSet::default());
assert_eq!(stack.buf.len(), stack.len)
}
self.len += 1;
if self.len > self.buf.len() {
push_empty_cold(self)
}
}
fn pop(&mut self) {
let Some(new_len) = self.len.checked_sub(1) else {
unreachable!("visible exprs stack underflow");
};
self.buf[new_len].clear();
self.len = new_len;
}
}
impl Default for VisibleExprsStack {
fn default() -> Self {
Self {
buf: Vec::new(),
len: 0,
}
}
}
struct AssertValidityState {
module: Module<Bundle>,
blocks: Vec<Block>,
visible_exprs: VisibleExprsStack,
target_states: HashMap<Interned<TargetBase>, TargetState>,
}
enum GetTargetStatesError {
NotFound,
IsGlobal,
FoundSimIoForGlobal(crate::expr::ops::SimIoForGlobal),
}
impl AssertValidityState {
fn make_block_index(&mut self, block: Block) -> usize {
let retval = self.blocks.len();
@ -1605,48 +1716,79 @@ impl AssertValidityState {
}
fn get_target_states<'a>(
&'a self,
target: &Target,
target: Target,
process_target_state: &dyn Fn(&'a TargetState, bool),
) -> Result<(), ()> {
match target {
Target::Base(target_base) => {
let target_state = self.get_base_state(*target_base)?;
process_target_state(target_state, false);
Ok(())
}
Target::Child(target_child) => self.get_target_states(
&target_child.parent(),
&|target_state, exact_target_unknown| {
let TargetStateInner::Decomposed { subtargets } = &target_state.inner else {
unreachable!(
"TargetState::new makes TargetState tree match the Target type"
);
};
match *target_child.path_element() {
TargetPathElement::BundleField(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("bundle fields filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::ArrayElement(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("array elements filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::DynArrayElement(_) => {
for target_state in subtargets.values() {
process_target_state(target_state, true);
) -> Result<(), GetTargetStatesError> {
let mut target = target.unwrap_transparent_types();
loop {
break match target {
Target::Base(target_base) => {
let target_state = self.get_base_state(target_base)?;
process_target_state(target_state, false);
Ok(())
}
Target::Child(target_child) => match *target_child.path_element() {
TargetPathElement::BundleField(_)
| TargetPathElement::ArrayElement(_)
| TargetPathElement::DynArrayElement(_) => self.get_target_states(
*target_child.parent(),
&|target_state, exact_target_unknown| {
let TargetStateInner::Decomposed { subtargets } = &target_state.inner
else {
unreachable!(
"TargetState::new makes TargetState tree match the Target type"
);
};
match *target_child.path_element() {
TargetPathElement::BundleField(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("bundle fields filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::ArrayElement(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("array elements filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::DynArrayElement(_) => {
for target_state in subtargets.values() {
process_target_state(target_state, true);
}
}
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => unreachable!(),
}
}
},
),
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => {
target = *target_child.parent();
continue;
}
},
),
};
}
}
fn get_base_state(&self, target_base: Interned<TargetBase>) -> Result<&TargetState, ()> {
self.target_states.get(&target_base).ok_or(())
fn get_base_state(
&self,
target_base: Interned<TargetBase>,
) -> Result<&TargetState, GetTargetStatesError> {
match *target_base {
TargetBase::ModuleIO(_)
| TargetBase::MemPort(_)
| TargetBase::Reg(_)
| TargetBase::RegSync(_)
| TargetBase::RegAsync(_)
| TargetBase::Wire(_)
| TargetBase::Instance(_) => self
.target_states
.get(&target_base)
.ok_or(GetTargetStatesError::NotFound),
TargetBase::FormalInput(_) => Err(GetTargetStatesError::IsGlobal),
TargetBase::SimIoForGlobal(v) => Err(GetTargetStatesError::FoundSimIoForGlobal(v)),
}
}
#[track_caller]
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
@ -1693,6 +1835,7 @@ impl AssertValidityState {
&TargetPathElement::BundleField(_) => {
let field = sub_target_state
.target
.without_trailing_transparent_path_elements()
.child()
.expect("known to be a child")
.bundle_field()
@ -1716,6 +1859,8 @@ impl AssertValidityState {
TargetPathElement::DynArrayElement { .. } => {
Self::set_connect_target_written(sub_target_state, is_lhs, block, true);
}
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => unreachable!("never added"),
}
}
}
@ -1733,19 +1878,33 @@ impl AssertValidityState {
debug_assert!(!is_lhs, "the ModuleBuilder asserts lhs.target().is_some()");
return;
};
let result = self.get_target_states(&target, &|target_state, exact_target_unknown| {
let result = self.get_target_states(*target, &|target_state, exact_target_unknown| {
Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown);
});
if result.is_err() {
if is_lhs {
panic!("at {source_location}: tried to connect to not-yet-defined item: {target}");
} else {
match result {
Ok(()) => {}
Err(GetTargetStatesError::NotFound) => {
if is_lhs {
panic!(
"at {source_location}: tried to connect to not-yet-defined item: {target}"
);
} else {
panic!(
"at {source_location}: tried to connect from not-yet-defined item: {target}"
);
}
}
Err(GetTargetStatesError::IsGlobal) => {
// no error
}
Err(GetTargetStatesError::FoundSimIoForGlobal(v)) => {
panic!(
"at {source_location}: tried to connect from not-yet-defined item: {target}"
);
"at {source_location}: fayalite::expr::ops::SimIoForGlobal is not allowed in Modules: {v:?}"
)
}
}
}
#[track_caller]
fn process_conditional_sub_blocks(
&mut self,
parent_block: usize,
@ -1759,17 +1918,40 @@ impl AssertValidityState {
}
}
#[track_caller]
fn assert_expr_validity<T: Type>(&mut self, expr: Expr<T>, source_location: SourceLocation) {
let mut visitor = AssertExprValidity { state: self };
match visitor.visit_expr(&expr) {
Ok(()) => {}
Err(e) => match e {
InvalidExpr::ExprIsNotVisible(expr) => {
if let Some(target) = expr.target() {
panic!(
"at {source_location}: expression isn't visible here, it's defined:\n\
at {}: {expr:?}",
target.base().source_location(),
);
} else {
panic!("at {source_location}: expression isn't visible here: {expr:?}");
}
}
},
}
}
#[track_caller]
fn assert_subtree_validity(&mut self, block: usize) {
self.visible_exprs.push_empty();
let module = self.module;
if block == 0 {
for module_io in &*module.module_io {
self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block);
self.visible_exprs.top().insert(module_io.module_io.into());
}
}
let Block { memories, stmts } = self.blocks[block];
for m in memories {
for port in m.ports() {
self.insert_new_base(TargetBase::intern_sized(port.into()), block);
self.visible_exprs.top().insert(port.into());
}
}
for stmt in stmts {
@ -1783,44 +1965,104 @@ impl AssertValidityState {
} = connect;
self.set_connect_side_written(lhs, source_location, true, block);
self.set_connect_side_written(rhs, source_location, false, block);
self.assert_expr_validity(lhs, source_location);
self.assert_expr_validity(rhs, source_location);
}
Stmt::Formal(formal) => {
let StmtFormal {
kind: _,
clk,
pred,
en,
text: _,
source_location,
} = formal;
self.assert_expr_validity(clk, source_location);
self.assert_expr_validity(pred, source_location);
self.assert_expr_validity(en, source_location);
}
Stmt::Formal(_) => {}
Stmt::If(if_stmt) => {
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
let StmtIf {
cond,
source_location,
blocks: sub_blocks,
} = if_stmt;
self.assert_expr_validity(cond, source_location);
let sub_blocks = sub_blocks.map(|block| self.make_block_index(block));
self.process_conditional_sub_blocks(block, sub_blocks)
}
Stmt::Match(match_stmt) => {
match_stmt.assert_validity();
let StmtMatch {
expr,
source_location,
blocks: sub_blocks,
} = match_stmt;
self.assert_expr_validity(expr, source_location);
let sub_blocks = Vec::from_iter(
match_stmt
.blocks
sub_blocks
.into_iter()
.map(|block| self.make_block_index(block)),
);
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied())
self.visible_exprs.push_empty();
let visible_exprs_top = self.visible_exprs.top();
for variant_index in 0..expr.ty().variants().len() {
visible_exprs_top
.insert(<VariantAccess>::new_by_index(expr, variant_index).into());
}
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied());
self.visible_exprs.pop();
}
Stmt::Declaration(StmtDeclaration::Wire(StmtWire {
annotations: _,
wire,
})) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block),
})) => {
self.insert_new_base(TargetBase::intern_sized(wire.into()), block);
self.visible_exprs.top().insert(wire.into());
}
Stmt::Declaration(StmtDeclaration::Reg(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::RegSync(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
annotations: _,
instance,
})) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block),
})) => {
self.insert_new_base(TargetBase::intern_sized(instance.into()), block);
self.visible_exprs.top().insert(instance.into());
}
}
}
self.visible_exprs.pop();
}
#[track_caller]
fn assert_validity(&mut self) {
@ -1849,6 +2091,143 @@ impl AssertValidityState {
}
}
struct AssertExprValidity<'a> {
state: &'a mut AssertValidityState,
}
enum InvalidExpr {
ExprIsNotVisible(Expr<CanonicalType>),
}
impl transform::visit::Visitor for AssertExprValidity<'_> {
type Error = InvalidExpr;
fn visit_expr_enum(&mut self, v: &ExprEnum) -> Result<(), Self::Error> {
match v {
ExprEnum::UIntLiteral(_)
| ExprEnum::SIntLiteral(_)
| ExprEnum::BoolLiteral(_)
| ExprEnum::PhantomConst(_)
| ExprEnum::BundleLiteral(_)
| ExprEnum::ArrayLiteral(_)
| ExprEnum::EnumLiteral(_)
| ExprEnum::Uninit(_)
| ExprEnum::NotU(_)
| ExprEnum::NotS(_)
| ExprEnum::NotB(_)
| ExprEnum::Neg(_)
| ExprEnum::BitAndU(_)
| ExprEnum::BitAndS(_)
| ExprEnum::BitAndB(_)
| ExprEnum::BitOrU(_)
| ExprEnum::BitOrS(_)
| ExprEnum::BitOrB(_)
| ExprEnum::BitXorU(_)
| ExprEnum::BitXorS(_)
| ExprEnum::BitXorB(_)
| ExprEnum::AddU(_)
| ExprEnum::AddS(_)
| ExprEnum::SubU(_)
| ExprEnum::SubS(_)
| ExprEnum::MulU(_)
| ExprEnum::MulS(_)
| ExprEnum::DivU(_)
| ExprEnum::DivS(_)
| ExprEnum::RemU(_)
| ExprEnum::RemS(_)
| ExprEnum::DynShlU(_)
| ExprEnum::DynShlS(_)
| ExprEnum::DynShrU(_)
| ExprEnum::DynShrS(_)
| ExprEnum::FixedShlU(_)
| ExprEnum::FixedShlS(_)
| ExprEnum::FixedShrU(_)
| ExprEnum::FixedShrS(_)
| ExprEnum::CmpLtB(_)
| ExprEnum::CmpLeB(_)
| ExprEnum::CmpGtB(_)
| ExprEnum::CmpGeB(_)
| ExprEnum::CmpEqB(_)
| ExprEnum::CmpNeB(_)
| ExprEnum::CmpLtU(_)
| ExprEnum::CmpLeU(_)
| ExprEnum::CmpGtU(_)
| ExprEnum::CmpGeU(_)
| ExprEnum::CmpEqU(_)
| ExprEnum::CmpNeU(_)
| ExprEnum::CmpLtS(_)
| ExprEnum::CmpLeS(_)
| ExprEnum::CmpGtS(_)
| ExprEnum::CmpGeS(_)
| ExprEnum::CmpEqS(_)
| ExprEnum::CmpNeS(_)
| ExprEnum::CastUIntToUInt(_)
| ExprEnum::CastUIntToSInt(_)
| ExprEnum::CastSIntToUInt(_)
| ExprEnum::CastSIntToSInt(_)
| ExprEnum::CastBoolToUInt(_)
| ExprEnum::CastBoolToSInt(_)
| ExprEnum::CastUIntToBool(_)
| ExprEnum::CastSIntToBool(_)
| ExprEnum::CastBoolToSyncReset(_)
| ExprEnum::CastUIntToSyncReset(_)
| ExprEnum::CastSIntToSyncReset(_)
| ExprEnum::CastBoolToAsyncReset(_)
| ExprEnum::CastUIntToAsyncReset(_)
| ExprEnum::CastSIntToAsyncReset(_)
| ExprEnum::CastSyncResetToBool(_)
| ExprEnum::CastSyncResetToUInt(_)
| ExprEnum::CastSyncResetToSInt(_)
| ExprEnum::CastSyncResetToReset(_)
| ExprEnum::CastAsyncResetToBool(_)
| ExprEnum::CastAsyncResetToUInt(_)
| ExprEnum::CastAsyncResetToSInt(_)
| ExprEnum::CastAsyncResetToReset(_)
| ExprEnum::CastResetToBool(_)
| ExprEnum::CastResetToUInt(_)
| ExprEnum::CastResetToSInt(_)
| ExprEnum::CastBoolToClock(_)
| ExprEnum::CastUIntToClock(_)
| ExprEnum::CastSIntToClock(_)
| ExprEnum::CastClockToBool(_)
| ExprEnum::CastClockToUInt(_)
| ExprEnum::CastClockToSInt(_)
| ExprEnum::FieldAccess(_)
| ExprEnum::ArrayIndex(_)
| ExprEnum::DynArrayIndex(_)
| ExprEnum::ReduceBitAndU(_)
| ExprEnum::ReduceBitAndS(_)
| ExprEnum::ReduceBitOrU(_)
| ExprEnum::ReduceBitOrS(_)
| ExprEnum::ReduceBitXorU(_)
| ExprEnum::ReduceBitXorS(_)
| ExprEnum::SliceUInt(_)
| ExprEnum::SliceSInt(_)
| ExprEnum::CastToBits(_)
| ExprEnum::CastBitsTo(_)
| ExprEnum::ToTraceAsString(_)
| ExprEnum::TraceAsStringAsInner(_)
| ExprEnum::StructuralEq(_)
| ExprEnum::FormalInput(_) => v.default_visit(self),
ExprEnum::VariantAccess(_)
| ExprEnum::ModuleIO(_)
| ExprEnum::Instance(_)
| ExprEnum::Wire(_)
| ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| ExprEnum::RegAsync(_)
| ExprEnum::MemPort(_) => {
if self.state.visible_exprs.contains(v) {
// no need to visit inner expressions, we already checked them before adding them to visible_exprs
Ok(())
} else {
Err(InvalidExpr::ExprIsNotVisible(v.to_expr()))
}
}
ExprEnum::SimIoForGlobal(_) => Err(InvalidExpr::ExprIsNotVisible(v.to_expr())),
}
}
}
impl<T: BundleType> Module<T> {
/// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead
#[track_caller]
@ -1974,6 +2353,7 @@ impl<T: BundleType> Module<T> {
AssertValidityState {
module: self.canonical(),
blocks: vec![],
visible_exprs: VisibleExprsStack::default(),
target_states: HashMap::with_capacity_and_hasher(64, Default::default()),
}
.assert_validity();
@ -2079,7 +2459,7 @@ impl<T: Type, R: ResetType> RegBuilder<Expr<ClockDomain<R>>, Option<Expr<T>>, T>
ty,
} = self;
ModuleBuilder::with(|module_builder| {
let scoped_name = ScopedNameId(module_builder.name, NameId(name, Id::new()));
let scoped_name = ScopedNameId(module_builder.name.into(), NameId(name, Id::new()));
let reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init);
let retval = reg.to_expr();
// convert before borrow_mut since ModuleBuilder could be reentered by T::canonical()
@ -2475,6 +2855,9 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
instance,
}
.into(),
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
unreachable!("not a valid annotation target")
}
};
ModuleBuilder::with(|m| {
unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt())
@ -2489,7 +2872,7 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
#[track_caller]
pub fn wire_with_loc<T: Type>(name: &str, source_location: SourceLocation, ty: T) -> Expr<T> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let wire = Wire::<T>::new_unchecked(scoped_name, source_location, ty);
let retval = wire.to_expr();
let canonical_wire = wire.canonical();
@ -2521,7 +2904,7 @@ fn incomplete_declaration(
source_location: SourceLocation,
) -> Rc<RefCell<IncompleteDeclaration>> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete {
name: scoped_name,
source_location,
@ -2697,7 +3080,7 @@ pub fn instance_with_loc<T: BundleType>(
source_location: SourceLocation,
) -> Expr<T> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let instance = Instance::<T> {
scoped_name,
instantiated,
@ -2736,7 +3119,7 @@ fn memory_impl<Element: Type, Len: Size>(
source_location: SourceLocation,
) -> MemBuilder<Element, Len> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type);
let mut impl_ = m.impl_.borrow_mut();
let body = impl_.body.builder_normal_body();
@ -2891,7 +3274,7 @@ impl<T: Type> ModuleIO<T> {
NameId(self.bundle_field.name, self.id)
}
pub fn scoped_name(&self) -> ScopedNameId {
ScopedNameId(self.containing_module_name, self.name_id())
ScopedNameId(self.containing_module_name.into(), self.name_id())
}
pub fn source_location(&self) -> SourceLocation {
self.source_location
@ -2964,10 +3347,102 @@ impl fmt::Debug for InstantiatedModule {
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub enum InstantiatedModuleOrGlobal {
Global,
InstantiatedModule(InstantiatedModule),
}
impl InstantiatedModuleOrGlobal {
pub fn leaf_module_source_location(self) -> SourceLocation {
match self {
Self::Global => SourceLocation::builtin(),
Self::InstantiatedModule(v) => v.leaf_module().source_location(),
}
}
}
impl From<InstantiatedModule> for InstantiatedModuleOrGlobal {
fn from(value: InstantiatedModule) -> Self {
Self::InstantiatedModule(value)
}
}
impl fmt::Debug for InstantiatedModuleOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Global => f.write_str("Global"),
Self::InstantiatedModule(v) => v.fmt(f),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct TargetInInstantiatedModule {
pub instantiated_module: InstantiatedModule,
pub target: Target,
pub struct TargetInInstantiatedModuleOrGlobal {
instantiated_module_or_global: InstantiatedModuleOrGlobal,
target: Target,
}
impl TargetInInstantiatedModuleOrGlobal {
#[track_caller]
pub fn new(instantiated_module_or_global: InstantiatedModuleOrGlobal, target: Target) -> Self {
match (
instantiated_module_or_global,
target.base().target_name().0.0,
) {
(InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::Global)
| (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::NameId(_)) => {
Self {
instantiated_module_or_global,
target,
}
}
(InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::NameId(_))
| (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::Global) => {
panic!(
"instantiated_module_or_global doesn't match target.base().target_name().0.0:\n\
instantiated_module_or_global: {instantiated_module_or_global:?}\n\
target: {target:?}"
)
}
}
}
#[track_caller]
pub fn from_target(
instantiated_module: impl Into<InstantiatedModuleOrGlobal>,
target: Target,
) -> Self {
let instantiated_module = instantiated_module.into();
Self {
instantiated_module_or_global: match target.base().target_name().0.0 {
NameIdOrGlobal::Global => InstantiatedModuleOrGlobal::Global,
NameIdOrGlobal::NameId(name_id) => {
let InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module) =
instantiated_module
else {
panic!(
"target is in a module, but no InstantiatedModule was provided: {target:#?}"
);
};
assert_eq!(
name_id,
instantiated_module.leaf_module().name_id(),
"target isn't contained in module:\n\
target: {target:#?}\n\
instantiated_module: {instantiated_module:?}",
);
InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module)
}
},
target,
}
}
pub fn instantiated_module_or_global(self) -> InstantiatedModuleOrGlobal {
self.instantiated_module_or_global
}
pub fn target(self) -> Target {
self.target
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]

View file

@ -10,7 +10,8 @@ use crate::{
ops::{self, ArrayLiteral},
target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
},
formal::FormalKind,
@ -26,6 +27,7 @@ use crate::{
prelude::*,
reset::{ResetType, ResetTypeDispatch},
sim::ExternModuleSimulation,
ty::TraceAsString,
util::{HashMap, HashSet},
};
use hashbrown::hash_map::Entry;
@ -103,6 +105,10 @@ enum ResetsLayout {
element: Interned<ResetsLayout>,
reset_count: usize,
},
Transparent {
inner: Interned<ResetsLayout>,
reset_count: usize,
},
}
impl ResetsLayout {
@ -112,7 +118,8 @@ impl ResetsLayout {
ResetsLayout::Reset | ResetsLayout::SyncReset | ResetsLayout::AsyncReset => 1,
ResetsLayout::Bundle { reset_count, .. }
| ResetsLayout::Enum { reset_count, .. }
| ResetsLayout::Array { reset_count, .. } => reset_count,
| ResetsLayout::Array { reset_count, .. }
| ResetsLayout::Transparent { reset_count, .. } => reset_count,
}
}
fn new(ty: CanonicalType) -> Self {
@ -166,6 +173,13 @@ impl ResetsLayout {
CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets,
CanonicalType::TraceAsString(ty) => {
let inner = ResetsLayout::new(ty.inner_ty()).intern_sized();
ResetsLayout::Transparent {
inner,
reset_count: inner.reset_count(),
}
}
}
}
}
@ -315,6 +329,12 @@ impl ResetGraph {
} => {
self.append_new_nodes_for_layout(*element, node_indexes, source_location);
}
ResetsLayout::Transparent {
inner,
reset_count: _,
} => {
self.append_new_nodes_for_layout(*inner, node_indexes, source_location);
}
}
}
}
@ -357,6 +377,21 @@ impl Resets {
node_indexes: self.node_indexes,
}
}
fn trace_as_string_inner(self) -> Self {
let trace_as_string = TraceAsString::from_canonical(self.ty);
let ResetsLayout::Transparent {
inner,
reset_count: _,
} = self.layout
else {
unreachable!();
};
Self {
ty: trace_as_string.inner_ty(),
layout: *inner,
node_indexes: self.node_indexes,
}
}
fn bundle_fields(self) -> impl Iterator<Item = Self> {
let bundle = Bundle::from_canonical(self.ty);
let ResetsLayout::Bundle {
@ -480,6 +515,17 @@ impl Resets {
CanonicalType::SyncReset(SyncReset)
},
),
CanonicalType::TraceAsString(ty) => Ok(CanonicalType::TraceAsString(
ty.with_new_inner_ty(
self.array_elements()
.substituted_type(
reset_graph,
fallback_to_sync_reset,
fallback_error_source_location,
)?
.intern_sized(),
),
)),
}
}
}
@ -1013,7 +1059,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
$(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
}
};
@ -1024,7 +1071,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(),
| CanonicalType::Reset(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => {
@ -1156,6 +1204,11 @@ impl<P: Pass> RunPass<P> for ExprEnum {
ExprEnum::SliceSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::CastToBits(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::CastBitsTo(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::TraceAsStringAsInner(expr) => {
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
}
ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
@ -1163,6 +1216,10 @@ impl<P: Pass> RunPass<P> for ExprEnum {
ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args),
ExprEnum::RegAsync(expr) => reg_expr_run_pass(expr, pass_args),
ExprEnum::MemPort(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::FormalInput(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::SimIoForGlobal(_) => {
unreachable!("Module is known to not contain SimIoForGlobal from validation")
}
}
}
}
@ -1536,6 +1593,100 @@ impl RunPassExpr for ops::CastBitsTo {
}
}
impl RunPassExpr for ops::TraceAsStringAsInner {
type Args<'a> = [Expr<CanonicalType>; 1];
fn args<'a>(&'a self) -> Self::Args<'a> {
[Expr::canonical(self.arg())]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(resets, args_resets[0].trace_as_string_inner(), None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::new(Expr::from_canonical(new_args[0])))
}
}
impl RunPassExpr for ops::ToTraceAsString {
type Args<'a> = [Expr<CanonicalType>; 1];
fn args<'a>(&'a self) -> Self::Args<'a> {
[Expr::canonical(self.inner())]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(resets.trace_as_string_inner(), args_resets[0], None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::new(
new_args[0],
self.ty().with_new_inner_ty(new_args[0].ty().intern_sized()),
))
}
}
impl RunPassExpr for ops::StructuralEq {
type Args<'a> = [Expr<CanonicalType>; 2];
fn args<'a>(&'a self) -> Self::Args<'a> {
[self.lhs(), self.rhs()]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
_resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(args_resets[0], args_resets[1], None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::new_unchecked(
new_args[0],
new_args[1],
self.assume_padding_is_zeroed(),
))
}
}
impl RunPassExpr for ModuleIO<CanonicalType> {
type Args<'a> = [Expr<CanonicalType>; 0];
@ -1691,7 +1842,8 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
}
})
}
@ -1818,6 +1970,7 @@ impl_run_pass_copy!([] SVAttributeAnnotation);
impl_run_pass_copy!([] UInt);
impl_run_pass_copy!([] usize);
impl_run_pass_copy!([] FormalKind);
impl_run_pass_copy!([] crate::formal::FormalInput);
impl_run_pass_copy!([] PhantomConst);
macro_rules! impl_run_pass_for_struct {
@ -2134,6 +2287,12 @@ impl<P: Pass> RunPass<P> for TargetBase {
&TargetBase::RegAsync(v) => v.into(),
TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)),
TargetBase::Instance(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Instance)),
TargetBase::FormalInput(v) => {
return Ok(v.run_pass(pass_args)?.map(TargetBase::FormalInput));
}
TargetBase::SimIoForGlobal(_) => {
unreachable!("Module is known to not contain SimIoForGlobal from validation")
}
};
Ok(reg.run_pass(pass_args)?.map(|reg| match reg {
AnyReg::Reg(reg) => TargetBase::Reg(reg),
@ -2173,30 +2332,6 @@ impl<P: Pass> RunPass<P> for StmtDeclaration {
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathBundleField {
name: _,
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathArrayElement {
index: _,
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathDynArrayElement {}
}
impl_run_pass_for_enum! {
impl[] RunPass for TargetPathElement {
BundleField(v),
ArrayElement(v),
DynArrayElement(v),
}
}
impl_run_pass_for_enum! {
impl[] RunPass for Target {
Base(v),
@ -2204,11 +2339,28 @@ impl_run_pass_for_enum! {
}
}
impl_run_pass_for_struct! {
#[constructor = TargetChild::new(parent, path_element)]
impl[] RunPass for TargetChild {
parent(): _,
path_element(): _,
impl<P: Pass> RunPass<P> for TargetChild {
fn run_pass(
&self,
mut pass_args: PassArgs<'_, P>,
) -> Result<PassOutput<Self, P>, DeduceResetsError> {
Ok(self.parent().run_pass(pass_args.as_mut())?.map(|parent| {
let path_element = match *self.path_element() {
TargetPathElement::BundleField(TargetPathBundleField { name: _ })
| TargetPathElement::ArrayElement(TargetPathArrayElement { index: _ })
| TargetPathElement::DynArrayElement(TargetPathDynArrayElement {})
| TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => {
self.path_element()
}
TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => {
TargetPathElement::from(TargetPathToTraceAsString {
ty: ty.with_new_inner_ty(parent.canonical_ty().intern_sized()),
})
.intern_sized()
}
};
TargetChild::new(parent, path_element)
}))
}
}

View file

@ -1,28 +1,23 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::{Array, ArrayType},
bundle::{Bundle, BundleField, BundleType},
enum_::{Enum, EnumType, EnumVariant},
bundle::{BundleField, BundleType},
enum_::{EnumType, EnumVariant},
expr::{
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
ops::{self, EnumLiteral},
ExprEnum,
ops::{self, EnumLiteral, StructuralEq},
},
hdl,
int::UInt,
intern::{Intern, InternSlice, Interned, Memoize},
memory::{DynPortType, Mem, MemPort},
memory::{DynPortType, MemPort},
module::{
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::visit::{Fold, Folder},
},
source_location::SourceLocation,
ty::{CanonicalType, Type},
prelude::*,
util::HashMap,
wire::Wire,
};
use core::fmt;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug)]
pub enum SimplifyEnumsError {
@ -64,6 +59,7 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool {
.fields()
.iter()
.any(|field| contains_any_enum_types(field.ty)),
CanonicalType::TraceAsString(ty) => contains_any_enum_types(ty.inner_ty()),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -95,11 +91,13 @@ enum EnumTypeState {
struct ModuleState {
module_name: NameId,
expr_cache: HashMap<ExprEnum, ExprEnum>,
source_location: SourceLocation,
}
impl ModuleState {
fn gen_name(&mut self, name: &str) -> ScopedNameId {
ScopedNameId(self.module_name, NameId(name.intern(), Id::new()))
ScopedNameId(self.module_name.into(), NameId(name.intern(), Id::new()))
}
}
@ -108,6 +106,45 @@ struct State {
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
kind: SimplifyEnumsKind,
module_state_stack: Vec<ModuleState>,
new_prefix_stmts_for_block: Vec<Stmt>,
new_suffix_stmts_for_block: Vec<Stmt>,
}
struct BlockScope<'a> {
state: &'a mut State,
parent_new_prefix_stmts_for_block: Vec<Stmt>,
parent_new_suffix_stmts_for_block: Vec<Stmt>,
}
impl<'a> BlockScope<'a> {
fn new(
state: &'a mut State,
new_prefix_stmts_for_block: Vec<Stmt>,
new_suffix_stmts_for_block: Vec<Stmt>,
) -> Self {
let parent_new_prefix_stmts_for_block = std::mem::replace(
&mut state.new_prefix_stmts_for_block,
new_prefix_stmts_for_block,
);
let parent_new_suffix_stmts_for_block = std::mem::replace(
&mut state.new_suffix_stmts_for_block,
new_suffix_stmts_for_block,
);
Self {
state,
parent_new_prefix_stmts_for_block,
parent_new_suffix_stmts_for_block,
}
}
}
impl Drop for BlockScope<'_> {
fn drop(&mut self) {
self.state.new_prefix_stmts_for_block =
std::mem::take(&mut self.parent_new_prefix_stmts_for_block);
self.state.new_suffix_stmts_for_block =
std::mem::take(&mut self.parent_new_suffix_stmts_for_block);
}
}
impl State {
@ -313,6 +350,24 @@ impl State {
}
Ok(())
}
fn handle_stmt_connect_trace_as_string(
&mut self,
unfolded_lhs_ty: TraceAsString,
unfolded_rhs_ty: TraceAsString,
folded_lhs: Expr<TraceAsString>,
folded_rhs: Expr<TraceAsString>,
source_location: SourceLocation,
output_stmts: &mut Vec<Stmt>,
) -> Result<(), SimplifyEnumsError> {
self.handle_stmt_connect(
unfolded_lhs_ty.inner_ty(),
unfolded_rhs_ty.inner_ty(),
ops::TraceAsStringAsInner::new(folded_lhs).to_expr(),
ops::TraceAsStringAsInner::new(folded_rhs).to_expr(),
source_location,
output_stmts,
)
}
fn handle_stmt_connect_bundle(
&mut self,
unfolded_lhs_ty: Bundle,
@ -509,6 +564,15 @@ impl State {
source_location,
output_stmts,
),
CanonicalType::TraceAsString(unfolded_lhs_ty) => self
.handle_stmt_connect_trace_as_string(
unfolded_lhs_ty,
TraceAsString::from_canonical(unfolded_rhs_ty),
Expr::from_canonical(folded_lhs),
Expr::from_canonical(folded_rhs),
source_location,
output_stmts,
),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -520,6 +584,208 @@ impl State {
| CanonicalType::DynSimOnly(_) => unreachable!(),
}
}
fn handle_enum_structural_eq(
&mut self,
unfolded_ty: Enum,
folded_lhs: Expr<CanonicalType>,
folded_rhs: Expr<CanonicalType>,
assume_padding_is_zeroed: bool,
) -> Result<Expr<Bool>, SimplifyEnumsError> {
if assume_padding_is_zeroed {
return Ok(StructuralEq::new_unchecked(
folded_lhs,
folded_rhs,
assume_padding_is_zeroed,
)
.to_expr());
}
let enum_type_state = self.get_or_make_enum_type_state(unfolded_ty)?;
if let EnumTypeState::Unchanged = enum_type_state {
return Ok(StructuralEq::new_unchecked(
folded_lhs,
folded_rhs,
assume_padding_is_zeroed,
)
.to_expr());
}
let module_state = self.module_state_stack.last_mut().unwrap();
let source_location = module_state.source_location;
let output_wire = Wire::new_unchecked(
module_state.gen_name("__enum_structural_eq"),
source_location,
Bool,
);
self.new_prefix_stmts_for_block.push(
StmtWire {
annotations: Interned::default(),
wire: output_wire.canonical(),
}
.into(),
);
let output_wire = output_wire.to_expr();
self.new_suffix_stmts_for_block.push(
StmtConnect {
lhs: Expr::canonical(output_wire),
rhs: Expr::canonical(false.to_expr()),
source_location,
}
.into(),
);
let tags_eq = match enum_type_state {
EnumTypeState::TagEnumAndBody(_) => StructuralEq::new_unchecked(
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_lhs).tag),
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_rhs).tag),
true,
)
.to_expr(),
EnumTypeState::TagUIntAndBody(_) => {
let lhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_lhs).tag;
let rhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_rhs).tag;
lhs.cmp_eq(rhs)
}
EnumTypeState::UInt(_) => {
let lhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_lhs)
[..unfolded_ty.discriminant_bit_width()];
let rhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_rhs)
[..unfolded_ty.discriminant_bit_width()];
lhs_int_tag_expr.cmp_eq(rhs_int_tag_expr)
}
EnumTypeState::Unchanged => unreachable!(),
};
let mut match_arms = Vec::with_capacity(unfolded_ty.variants().len());
for (variant_index, variant) in unfolded_ty.variants().iter().enumerate() {
let block_scope = BlockScope::new(self, vec![], vec![]);
let this = &mut *block_scope.state;
let eq = if let Some(variant_ty) = variant.ty {
let folded_lhs =
this.handle_variant_access(unfolded_ty, folded_lhs, variant_index)?;
let folded_rhs =
this.handle_variant_access(unfolded_ty, folded_rhs, variant_index)?;
this.handle_structural_eq(
variant_ty,
folded_lhs,
folded_rhs,
assume_padding_is_zeroed,
)?
} else {
true.to_expr()
};
match_arms.push(Block {
memories: [].intern_slice(),
stmts: this
.new_prefix_stmts_for_block
.drain(..)
.chain([StmtConnect {
lhs: Expr::canonical(output_wire),
rhs: Expr::canonical(eq),
source_location,
}
.into()])
.chain(this.new_suffix_stmts_for_block.drain(..))
.collect(),
});
}
let match_stmt =
self.handle_match(unfolded_ty, folded_lhs, source_location, &match_arms)?;
self.new_suffix_stmts_for_block.push(
StmtIf {
cond: tags_eq,
source_location,
blocks: [
Block {
memories: [].intern_slice(),
stmts: [match_stmt].intern_slice(),
},
Block {
memories: [].intern_slice(),
stmts: [].intern_slice(),
},
],
}
.into(),
);
Ok(output_wire)
}
fn handle_structural_eq(
&mut self,
unfolded_ty: CanonicalType,
folded_lhs: Expr<CanonicalType>,
folded_rhs: Expr<CanonicalType>,
assume_padding_is_zeroed: bool,
) -> Result<Expr<Bool>, SimplifyEnumsError> {
if !contains_any_enum_types(unfolded_ty) {
return Ok(StructuralEq::new_unchecked(
folded_lhs,
folded_rhs,
assume_padding_is_zeroed,
)
.to_expr());
}
match unfolded_ty {
CanonicalType::Array(unfolded_ty) => {
let unfolded_element_ty = unfolded_ty.element();
let mut retval = None;
for i in 0..unfolded_ty.len() {
let element_eq = self.handle_structural_eq(
unfolded_element_ty,
ops::ArrayIndex::new(Expr::from_canonical(folded_lhs), i).to_expr(),
ops::ArrayIndex::new(Expr::from_canonical(folded_rhs), i).to_expr(),
assume_padding_is_zeroed,
)?;
retval = Some(match retval {
Some(old_eq) => old_eq & element_eq,
None => element_eq,
});
}
Ok(retval.unwrap_or_else(|| {
StructuralEq::new_unchecked(folded_lhs, folded_rhs, assume_padding_is_zeroed)
.to_expr()
}))
}
CanonicalType::Enum(unfolded_ty) => self.handle_enum_structural_eq(
unfolded_ty,
folded_lhs,
folded_rhs,
assume_padding_is_zeroed,
),
CanonicalType::Bundle(unfolded_ty) => {
let mut retval = None;
for (i, field) in unfolded_ty.fields().iter().enumerate() {
let field_eq = self.handle_structural_eq(
field.ty,
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_lhs), i)
.to_expr(),
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_rhs), i)
.to_expr(),
assume_padding_is_zeroed,
)?;
retval = Some(match retval {
Some(old_eq) => old_eq & field_eq,
None => field_eq,
});
}
Ok(retval.unwrap_or_else(|| {
StructuralEq::new_unchecked(folded_lhs, folded_rhs, assume_padding_is_zeroed)
.to_expr()
}))
}
CanonicalType::TraceAsString(unfolded_ty) => self.handle_structural_eq(
unfolded_ty.inner_ty(),
*Expr::<TraceAsString>::from_canonical(folded_lhs),
*Expr::<TraceAsString>::from_canonical(folded_rhs),
assume_padding_is_zeroed,
),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!("doesn't contain any enum types"),
}
}
}
fn connect_port(
@ -528,6 +794,8 @@ fn connect_port(
rhs: Expr<CanonicalType>,
source_location: SourceLocation,
) {
let lhs = Expr::unwrap_transparent_types(lhs);
let rhs = Expr::unwrap_transparent_types(rhs);
if lhs.ty() == rhs.ty() {
stmts.push(
StmtConnect {
@ -573,6 +841,9 @@ fn connect_port(
connect_port(stmts, lhs[index], rhs[index], source_location);
}
}
(CanonicalType::TraceAsString(_), CanonicalType::TraceAsString(_)) => {
unreachable!("handled by unwrap_transparent_types")
}
(CanonicalType::Bundle(_), _)
| (CanonicalType::Enum(_), _)
| (CanonicalType::Array(_), _)
@ -584,7 +855,8 @@ fn connect_port(
| (CanonicalType::SyncReset(_), _)
| (CanonicalType::Reset(_), _)
| (CanonicalType::PhantomConst(_), _)
| (CanonicalType::DynSimOnly(_), _) => unreachable!(
| (CanonicalType::DynSimOnly(_), _)
| (CanonicalType::TraceAsString(_), _) => unreachable!(
"trying to connect memory ports:\n{:?}\n{:?}",
lhs.ty(),
rhs.ty(),
@ -641,6 +913,8 @@ impl Folder for State {
fn fold_module<T: BundleType>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error> {
self.module_state_stack.push(ModuleState {
module_name: v.name_id(),
expr_cache: HashMap::default(),
source_location: v.source_location(),
});
let retval = Fold::default_fold(v, self);
self.module_state_stack.pop();
@ -648,30 +922,51 @@ impl Folder for State {
}
fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
match op {
if let Some(folded_op) = self
.module_state_stack
.last()
.expect("known to be in module")
.expr_cache
.get(&op)
{
return Ok(*folded_op);
}
let folded_op = match op {
ExprEnum::EnumLiteral(op) => {
let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?;
Ok(*Expr::expr_enum(self.handle_enum_literal(
*Expr::expr_enum(self.handle_enum_literal(
op.ty(),
op.variant_index(),
folded_variant_value,
)?))
)?)
}
ExprEnum::VariantAccess(op) => {
let folded_base_expr = Expr::canonical(op.base()).fold(self)?;
Ok(*Expr::expr_enum(self.handle_variant_access(
*Expr::expr_enum(self.handle_variant_access(
op.base().ty(),
folded_base_expr,
op.variant_index(),
)?))
)?)
}
ExprEnum::MemPort(mem_port) => Ok(
ExprEnum::StructuralEq(op) => {
let ty = op.lhs().ty();
assert_eq!(ty, op.rhs().ty());
let folded_lhs = Expr::canonical(op.lhs()).fold(self)?;
let folded_rhs = Expr::canonical(op.rhs()).fold(self)?;
*Expr::expr_enum(self.handle_structural_eq(
ty,
folded_lhs,
folded_rhs,
op.assume_padding_is_zeroed(),
)?)
}
ExprEnum::MemPort(mem_port) => {
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
ExprEnum::Wire(wire)
} else {
ExprEnum::MemPort(mem_port.fold(self)?)
},
),
}
}
ExprEnum::UIntLiteral(_)
| ExprEnum::SIntLiteral(_)
| ExprEnum::BoolLiteral(_)
@ -772,21 +1067,33 @@ impl Folder for State {
| ExprEnum::SliceSInt(_)
| ExprEnum::CastToBits(_)
| ExprEnum::CastBitsTo(_)
| ExprEnum::TraceAsStringAsInner(_)
| ExprEnum::ToTraceAsString(_)
| ExprEnum::ModuleIO(_)
| ExprEnum::Instance(_)
| ExprEnum::Wire(_)
| ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| ExprEnum::RegAsync(_) => op.default_fold(self),
}
| ExprEnum::RegAsync(_)
| ExprEnum::FormalInput(_)
| ExprEnum::SimIoForGlobal(_) => op.default_fold(self)?,
};
self.module_state_stack
.last_mut()
.expect("known to be in module")
.expr_cache
.insert(op, folded_op);
Ok(folded_op)
}
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
let block_scope = BlockScope::new(self, vec![], vec![]);
let this = &mut *block_scope.state;
let mut memories = vec![];
let mut stmts = vec![];
for memory in block.memories {
let old_element_ty = memory.array_type().element();
let new_element_ty = memory.array_type().element().fold(self)?;
let new_element_ty = memory.array_type().element().fold(this)?;
if new_element_ty != old_element_ty {
let mut new_ports = vec![];
for port in memory.ports() {
@ -812,7 +1119,7 @@ impl Folder for State {
continue;
}
let wire = Wire::new_unchecked(
self.module_state_stack
this.module_state_stack
.last_mut()
.unwrap()
.gen_name(&format!(
@ -836,7 +1143,7 @@ impl Folder for State {
Expr::canonical(wire.to_expr()),
port.source_location(),
);
self.replacement_mem_ports.insert(port, wire.canonical());
this.replacement_mem_ports.insert(port, wire.canonical());
}
memories.push(Mem::new_unchecked(
memory.scoped_name(),
@ -851,10 +1158,12 @@ impl Folder for State {
memory.mem_annotations(),
));
} else {
memories.push(memory.fold(self)?);
memories.push(memory.fold(this)?);
}
}
stmts.extend_from_slice(&block.stmts.fold(self)?);
stmts.extend_from_slice(&block.stmts.fold(this)?);
stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..));
stmts.extend_from_slice(&this.new_suffix_stmts_for_block);
Ok(Block {
memories: Intern::intern_owned(memories),
stmts: Intern::intern_owned(stmts),
@ -936,7 +1245,8 @@ impl Folder for State {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => canonical_type.default_fold(self),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => canonical_type.default_fold(self),
}
}
@ -975,10 +1285,13 @@ pub fn simplify_enums(
module: Interned<Module<Bundle>>,
kind: SimplifyEnumsKind,
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
// TODO: deduce StructuralEq's assume_padding_is_zeroed
module.fold(&mut State {
enum_types: HashMap::default(),
replacement_mem_ports: HashMap::default(),
kind,
module_state_stack: vec![],
new_prefix_stmts_for_block: vec![],
new_suffix_stmts_for_block: vec![],
})
}

View file

@ -90,7 +90,7 @@ impl MemSplit {
}
}
fn new(element_type: CanonicalType) -> Self {
match element_type {
match element_type.unwrap_transparent_types() {
CanonicalType::Bundle(bundle_ty) => MemSplit::Bundle {
fields: bundle_ty
.fields()
@ -195,6 +195,7 @@ impl MemSplit {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"),
}
}
}
@ -306,7 +307,9 @@ impl SplitMemState<'_, '_> {
let outer_mem_name_path_len = self.mem_name_path.len();
match self.split {
MemSplit::Bundle { fields } => {
let CanonicalType::Bundle(bundle_type) = self.element_type else {
let CanonicalType::Bundle(bundle_type) =
self.element_type.unwrap_transparent_types()
else {
unreachable!();
};
for ((field, field_offset), split) in bundle_type
@ -321,7 +324,10 @@ impl SplitMemState<'_, '_> {
let field_ty_bit_width = field.ty.bit_width();
self.split_state_stack.push_map(
|e: Expr<CanonicalType>| {
Expr::field(Expr::<Bundle>::from_canonical(e), &field.name)
Expr::field(
Expr::<Bundle>::from_canonical(Expr::unwrap_transparent_types(e)),
&field.name,
)
},
|initial_value_element| {
let Some(field_offset) = field_offset.only_bit_width() else {
@ -377,8 +383,8 @@ impl SplitMemState<'_, '_> {
};
self.output_stmts.push(
StmtConnect {
lhs: Expr::field(port_expr, name),
rhs: Expr::field(wire_expr, name),
lhs: Expr::unwrap_transparent_types(Expr::field(port_expr, name)),
rhs: Expr::unwrap_transparent_types(Expr::field(wire_expr, name)),
source_location: port.source_location(),
}
.into(),
@ -389,7 +395,8 @@ impl SplitMemState<'_, '_> {
self.output_mems.push(new_mem);
}
MemSplit::Array { elements } => {
let CanonicalType::Array(array_type) = self.element_type else {
let CanonicalType::Array(array_type) = self.element_type.unwrap_transparent_types()
else {
unreachable!();
};
let element_type = array_type.element();
@ -398,7 +405,7 @@ impl SplitMemState<'_, '_> {
self.mem_name_path.truncate(outer_mem_name_path_len);
write!(self.mem_name_path, "_{index}").unwrap();
self.split_state_stack.push_map(
|e| Expr::<Array>::from_canonical(e)[index],
|e| Expr::<Array>::from_canonical(Expr::unwrap_transparent_types(e))[index],
|initial_value_element| {
&initial_value_element[index * element_bit_width..][..element_bit_width]
},
@ -464,7 +471,7 @@ impl ModuleState {
assert_eq!(memory_element_array_range_len % input_array_type.len(), 0);
let chunk_size = memory_element_array_range_len / input_array_type.len();
for index in 0..input_array_type.len() {
let map = |e| Expr::<Array>::from_canonical(e)[index];
let map = |e| Expr::<Array>::from_canonical(Expr::unwrap_transparent_types(e))[index];
let wire_rdata = wire_rdata.map(map);
let wire_wdata = wire_wdata.map(map);
let wire_wmask = wire_wmask.map(map);
@ -505,8 +512,8 @@ impl ModuleState {
port_read: Expr<CanonicalType>| {
output_stmts.push(
StmtConnect {
lhs: wire_read,
rhs: port_read,
lhs: Expr::unwrap_transparent_types(wire_read),
rhs: Expr::unwrap_transparent_types(port_read),
source_location,
}
.into(),
@ -517,8 +524,8 @@ impl ModuleState {
port_write: Expr<CanonicalType>| {
output_stmts.push(
StmtConnect {
lhs: port_write,
rhs: wire_write,
lhs: Expr::unwrap_transparent_types(port_write),
rhs: Expr::unwrap_transparent_types(wire_write),
source_location,
}
.into(),
@ -530,7 +537,8 @@ impl ModuleState {
connect_read(
output_stmts,
wire_read,
Expr::<UInt>::from_canonical(port_read).cast_bits_to(wire_read.ty()),
Expr::<UInt>::from_canonical(Expr::unwrap_transparent_types(port_read))
.cast_bits_to(wire_read.ty()),
);
};
let connect_write_enum =
@ -544,7 +552,7 @@ impl ModuleState {
);
};
loop {
match input_element_type {
match input_element_type.unwrap_transparent_types() {
CanonicalType::Bundle(_) => {
unreachable!("bundle types are always split")
}
@ -625,6 +633,9 @@ impl ModuleState {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
CanonicalType::TraceAsString(_) => {
unreachable!("handled by unwrap_transparent_types")
}
}
break;
}

View file

@ -14,16 +14,17 @@ use crate::{
Expr, ExprEnum, ValueType, ops,
target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
},
formal::FormalKind,
formal::{FormalInput, FormalInputKind, FormalKind},
int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
module::{
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId, NameIdOrGlobal,
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
StmtInstance, StmtMatch, StmtReg, StmtWire,
},
@ -32,7 +33,7 @@ use crate::{
reset::{AsyncReset, Reset, ResetType, SyncReset},
sim::{ExternModuleSimulation, value::DynSimOnly},
source_location::SourceLocation,
ty::{CanonicalType, Type},
ty::{CanonicalType, TraceAsString, Type},
vendor::xilinx::{
XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation,
},
@ -481,4 +482,30 @@ impl<T: ?Sized + Visit<State>, State: ?Sized + Visitor> Visit<State> for &'_ mut
}
}
impl<State: ?Sized + Visitor> Visit<State> for NameIdOrGlobal {
fn visit(&self, state: &mut State) -> Result<(), <State>::Error> {
state.visit_name_id_or_global(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), <State>::Error> {
match self {
Self::Global => Ok(()),
Self::NameId(name_id) => name_id.visit(state),
}
}
}
impl<State: ?Sized + Folder> Fold<State> for NameIdOrGlobal {
fn fold(self, state: &mut State) -> Result<Self, <State>::Error> {
state.fold_name_id_or_global(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, <State>::Error> {
match self {
Self::Global => Ok(Self::Global),
Self::NameId(name_id) => Ok(Self::NameId(name_id.fold(state)?)),
}
}
}
include!(concat!(env!("OUT_DIR"), "/visit.rs"));

View file

@ -384,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
}
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
const STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
lhs: Self,

View file

@ -13,11 +13,11 @@ pub use crate::{
enum_::{Enum, HdlNone, HdlOption, HdlSome},
expr::{
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr,
ReduceBits, ToExpr, ValueType, repeat,
ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat,
},
formal::{
MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset,
hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert,
hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
hdl_cover_with_enable,
},
hdl, hdl_module,
@ -37,8 +37,8 @@ pub use crate::{
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
},
source_location::SourceLocation,
testing::{FormalMode, assert_formal},
ty::{AsMask, CanonicalType, Type},
testing::{FormalMode, assert_formal, checked_vcd_output},
ty::{AsMask, CanonicalType, TraceAsString, Type},
util::{ConstUsize, GenericConstUsize},
wire::Wire,
};

View file

@ -79,6 +79,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
if let Some(init) = init {
assert_eq!(ty, init.ty(), "register's type must match init type");
}
scoped_name.0.assert_is_name_id();
Self {
name: scoped_name,
source_location,
@ -94,7 +95,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0
self.name.0.unwrap_name_id()
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,9 @@ use crate::{
int::{BoolOrIntType, SInt, UInt},
intern::{Intern, Interned, Memoize},
sim::interpreter::parts::{
StateLayout, StatePartIndex, StatePartKind, StatePartKindBigSlots, StatePartKindMemories,
StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen, TypeIndexRange,
TypeLayout, get_state_part_kinds,
StateLayout, StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots,
StatePartKindMemories, StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen,
TypeIndexRange, TypeLayout, get_state_part_kinds,
},
source_location::SourceLocation,
util::{HashMap, HashSet},
@ -920,6 +920,12 @@ impl<K: StatePartKind> StatePart<K> {
) -> bool {
K::state_index_fetch_maybe_modified_flag(&self.value, part_index)
}
pub(crate) fn state_index_range_fetch_maybe_modified_flags(
&self,
part_index_range: StatePartIndexRange<K>,
) -> bool {
K::state_index_range_fetch_maybe_modified_flags(&self.value, part_index_range)
}
pub(crate) fn clear_all_maybe_modified_flags(&mut self) {
K::clear_all_maybe_modified_flags(&mut self.value)
}
@ -974,6 +980,7 @@ macro_rules! make_state {
pub(crate) insns: Interned<Insns<InsnsBuildingDone>>,
pub(crate) pc: usize,
pub(crate) memory_write_log: Vec<(StatePartIndex<StatePartKindMemories>, usize)>,
pub(crate) assert_failed_log: Vec<usize>,
$(pub(crate) $state_plural_field: StatePart<$state_kind>,)*
$(pub(crate) $type_plural_field: StatePart<$type_kind>,)*
}
@ -984,6 +991,7 @@ macro_rules! make_state {
insns: _,
pc,
memory_write_log,
assert_failed_log,
$($state_plural_field,)*
$($type_plural_field,)*
} = self;
@ -991,6 +999,7 @@ macro_rules! make_state {
.field("insns", &InsnsOfState(self))
.field("pc", pc)
.field("memory_write_log", memory_write_log)
.field("assert_failed_log", assert_failed_log)
$(.field(stringify!($state_plural_field), $state_plural_field))*
$(.field(stringify!($type_plural_field), $type_plural_field))*
.finish()
@ -1003,6 +1012,7 @@ macro_rules! make_state {
insns,
pc: 0,
memory_write_log: Vec::with_capacity(32),
assert_failed_log: Vec::new(),
$($state_plural_field: StatePart::new(&insns.state_layout.$state_plural_field.layout_data),)*
$($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)*
}
@ -1014,10 +1024,16 @@ macro_rules! make_state {
pc: self.pc,
orig_pc: &mut self.pc,
memory_write_log: &mut self.memory_write_log,
assert_failed_log: &mut self.assert_failed_log,
$($state_plural_field: self.$state_plural_field.borrow(),)*
$($type_plural_field: self.$type_plural_field.borrow(),)*
}
}
pub(crate) fn type_index_range_fetch_maybe_modified_flags(&self, range: TypeIndexRange) -> bool {
$(self.$type_plural_field.state_index_range_fetch_maybe_modified_flags(
range.$type_plural_field,
))||*
}
pub(crate) fn clear_all_maybe_modified_flags(&mut self) {
$(self.$state_plural_field.clear_all_maybe_modified_flags();)*
$(self.$type_plural_field.clear_all_maybe_modified_flags();)*
@ -1031,6 +1047,7 @@ macro_rules! make_state {
pub(crate) orig_pc: &'a mut usize,
pub(crate) pc: usize,
pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex<StatePartKindMemories>, usize)>,
pub(crate) assert_failed_log: &'a mut Vec<usize>,
$(pub(crate) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)*
$(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)*
}
@ -1288,6 +1305,7 @@ impl State {
insns: _,
pc,
memory_write_log: _,
assert_failed_log: _,
memories: _,
small_slots: _,
big_slots: _,
@ -1327,6 +1345,10 @@ impl BorrowedState<'_> {
self.memory_write_log.push(log_entry);
}
}
#[cold]
fn assert_failed(&mut self, assert_index: usize) {
self.assert_failed_log.push(assert_index);
}
}
fn bigint_pow2(width: usize) -> Interned<BigInt> {
@ -2094,6 +2116,19 @@ impl_insns! {
state.log_memory_write(memory, addr);
next!();
}
Assert {
#[kind = Input]
clk_triggered: StatePartIndex<StatePartKindSmallSlots>,
#[kind = Input]
pred: StatePartIndex<StatePartKindSmallSlots>,
#[kind = Immediate]
assert_index: usize,
} => {
if state.small_slots[clk_triggered] != 0 && state.small_slots[pred] == 0 {
state.assert_failed(assert_index);
}
next!();
}
Return => {
break RunResult::Return(());
}

View file

@ -260,6 +260,10 @@ pub(crate) trait StatePartKind:
state: &Self::State,
part_index: StatePartIndex<Self>,
) -> bool;
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool;
fn clear_all_maybe_modified_flags(state: &mut Self::State);
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
@ -342,6 +346,12 @@ impl StatePartKind for StatePartKindMemories {
) -> bool {
true
}
fn state_index_range_fetch_maybe_modified_flags(
_state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
part_index_range.len.value > 0
}
fn clear_all_maybe_modified_flags(_state: &mut Self::State) {}
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
@ -446,6 +456,14 @@ impl StatePartKind for StatePartKindSmallSlots {
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}
@ -530,6 +548,14 @@ impl StatePartKind for StatePartKindBigSlots {
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}
@ -614,6 +640,14 @@ impl StatePartKind for StatePartKindSimOnlySlots {
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}

View file

@ -19,20 +19,19 @@ use crate::{
impl_match_variant_as_self,
},
util::{
ConstUsize, HashMap,
ConstUsize,
alternating_cell::{AlternatingCell, AlternatingCellMethods},
serde_by_id::{SerdeById, SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait},
},
};
use bitvec::{slice::BitSlice, vec::BitVec};
use hashbrown::hash_map::Entry;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
use std::{
borrow::{Borrow, BorrowMut, Cow},
fmt::{self, Write},
hash::{BuildHasher, Hash, Hasher, RandomState},
fmt,
num::NonZero,
ops::{Deref, DerefMut, Index, IndexMut},
sync::{Arc, Mutex},
sync::Arc,
};
pub(crate) mod sim_only_value_unsafe;
@ -1098,7 +1097,8 @@ impl ToSimValueWithType<CanonicalType> for bool {
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => {
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => {
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
}
CanonicalType::Bool(_)
@ -1227,80 +1227,17 @@ macro_rules! impl_to_sim_value_for_int_value {
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
#[derive(Default)]
struct DynSimOnlySerdeTableRest {
from_serde: HashMap<DynSimOnlySerdeId, DynSimOnly>,
serde_id_random_state: RandomState,
buffer: String,
}
impl DynSimOnlySerdeTableRest {
#[cold]
fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId {
let mut try_number = 0u64;
let mut hasher = self.serde_id_random_state.build_hasher();
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail");
self.buffer.hash(&mut hasher);
loop {
let mut hasher = hasher.clone();
try_number.hash(&mut hasher);
try_number += 1;
let retval = DynSimOnlySerdeId(std::array::from_fn(|i| {
let mut hasher = hasher.clone();
i.hash(&mut hasher);
hasher.finish() as u32
}));
match self.from_serde.entry(retval) {
Entry::Occupied(_) => continue,
Entry::Vacant(e) => {
e.insert(ty);
return retval;
}
}
}
impl SerdeByIdTrait for DynSimOnly {
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Self> {
self.serde_by_id_properties_inner()
}
}
#[derive(Default)]
struct DynSimOnlySerdeTable {
to_serde: HashMap<DynSimOnly, DynSimOnlySerdeId>,
rest: DynSimOnlySerdeTableRest,
}
static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlySerdeTable>> = Mutex::new(None);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct DynSimOnlySerdeId([u32; 4]);
impl From<DynSimOnly> for DynSimOnlySerdeId {
fn from(ty: DynSimOnly) -> Self {
let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
let DynSimOnlySerdeTable { to_serde, rest } = locked.get_or_insert_default();
match to_serde.entry(ty) {
Entry::Occupied(occupied_entry) => *occupied_entry.get(),
Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)),
}
fn static_table() -> &'static SerdeByIdTable<Self> {
static TABLE: SerdeByIdTable<DynSimOnly> = SerdeByIdTable::new();
&TABLE
}
}
impl DynSimOnlySerdeId {
fn ty(self) -> Option<DynSimOnly> {
let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
Some(*locked.as_ref()?.rest.from_serde.get(&self)?)
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
struct DynSimOnlySerde<'a> {
random_id: DynSimOnlySerdeId,
#[serde(borrow)]
type_name: Cow<'a, str>,
const NAME: &'static str = "DynSimOnly";
}
impl Serialize for DynSimOnly {
@ -1308,11 +1245,7 @@ impl Serialize for DynSimOnly {
where
S: Serializer,
{
DynSimOnlySerde {
random_id: (*self).into(),
type_name: Cow::Borrowed(self.type_name()),
}
.serialize(serializer)
SerdeById { inner: *self }.serialize(serializer)
}
}
@ -1321,16 +1254,7 @@ impl<'de> Deserialize<'de> for DynSimOnly {
where
D: Deserializer<'de>,
{
let deserialized = DynSimOnlySerde::deserialize(deserializer)?;
let retval = deserialized
.random_id
.ty()
.filter(|ty| ty.type_name() == deserialized.type_name);
retval.ok_or_else(|| {
D::Error::custom(
"doesn't match any DynSimOnly that was serialized this time this program was run",
)
})
Ok(SerdeById::deserialize(deserializer)?.inner)
}
}
@ -1584,6 +1508,8 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
}
impl HdlPartialEqImpl<Self> for DynSimOnly {
const STRUCTURAL_EQ: bool = false;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -1603,6 +1529,8 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
for SimOnly<L>
{
const STRUCTURAL_EQ: bool = false;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,

View file

@ -3,7 +3,10 @@
//! `unsafe` parts of [`DynSimOnlyValue`]
use crate::expr::{ValueType, value_category::ValueCategoryValue};
use crate::{
expr::{ValueType, value_category::ValueCategoryValue},
util::serde_by_id::SerdeByIdProperties,
};
use serde::{Serialize, de::DeserializeOwned};
use std::{
any::{self, TypeId},
@ -33,6 +36,7 @@ unsafe trait DynSimOnlyTrait: 'static + Send + Sync {
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>>;
fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties<DynSimOnly>;
}
/// Safety: `type_id_dyn` is implemented correctly
@ -55,6 +59,9 @@ unsafe impl<T: SimOnlyValueTrait> DynSimOnlyTrait for SimOnly<T> {
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>> {
Ok(Rc::<T>::new(serde_json::from_str(json_str)?))
}
fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties<DynSimOnly> {
SerdeByIdProperties::of::<T>()
}
}
/// Safety:
@ -151,6 +158,9 @@ impl DynSimOnly {
pub fn default_value(self) -> DynSimOnlyValue {
DynSimOnlyValue(self.ty.default_value())
}
pub(super) fn serde_by_id_properties_inner(self) -> SerdeByIdProperties<Self> {
self.ty.serde_by_id_properties_inner()
}
}
impl PartialEq for DynSimOnly {

View file

@ -9,14 +9,15 @@ use crate::{
prelude::PhantomConst,
sim::{
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, TraceScalarId,
TraceScope, TraceSimOnly, TraceSyncReset, TraceUInt, TraceWire, TraceWriter,
TraceWriterDecls,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceFormalInput,
TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation,
TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar,
TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt,
TraceWire, TraceWriter, TraceWriterDecls,
time::{SimDuration, SimInstant},
value::DynSimOnlyValue,
},
ty::{OpaqueSimValueSlice, TraceAsString},
util::HashMap,
};
use bitvec::{order::Lsb0, slice::BitSlice};
@ -331,6 +332,7 @@ impl WriteTrace for TraceScalar {
Self::AsyncReset(v) => v.write_trace(writer, arg),
Self::PhantomConst(v) => v.write_trace(writer, arg),
Self::SimOnly(v) => v.write_trace(writer, arg),
Self::TraceAsString(v) => v.write_trace(writer, arg),
}
}
}
@ -726,6 +728,34 @@ impl WriteTrace for TraceSimOnly {
}
}
impl WriteTrace for TraceTraceAsString {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
source_var_type: _,
sink_var_type: _,
duplex_var_type: _,
properties,
scope,
} = arg.in_type();
let Self {
location,
name,
ty,
flow: _,
} = self;
write_vcd_var(
properties,
scope,
MemoryElementPartBody::TraceAsString { ty },
writer,
"string",
1,
location,
name,
)
}
}
impl WriteTrace for TraceScope {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
match self {
@ -736,6 +766,7 @@ impl WriteTrace for TraceScope {
Self::Wire(v) => v.write_trace(writer, arg),
Self::Reg(v) => v.write_trace(writer, arg),
Self::ModuleIO(v) => v.write_trace(writer, arg),
Self::FormalInput(v) => v.write_trace(writer, arg),
Self::Bundle(v) => v.write_trace(writer, arg),
Self::Array(v) => v.write_trace(writer, arg),
Self::EnumWithFields(v) => v.write_trace(writer, arg),
@ -933,6 +964,27 @@ impl WriteTrace for TraceModuleIO {
}
}
impl WriteTrace for TraceFormalInput {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body();
let Self {
name: _,
child,
formal_input: _,
} = self;
child.write_trace(
writer,
ArgInType {
source_var_type: "wire",
sink_var_type: "wire",
duplex_var_type: "wire",
properties,
scope: Some(scope),
},
)
}
}
impl WriteTrace for TraceBundle {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
@ -1093,6 +1145,7 @@ impl<W: io::Write> TraceWriterDecls for VcdWriterDecls<W> {
finished_init: false,
timescale,
properties,
trace_as_string_buf: String::with_capacity(256),
})
}
}
@ -1100,6 +1153,7 @@ impl<W: io::Write> TraceWriterDecls for VcdWriterDecls<W> {
enum MemoryElementPartBody {
Scalar,
EnumDiscriminant { ty: Enum },
TraceAsString { ty: TraceAsString },
}
struct MemoryElementPart {
@ -1217,6 +1271,7 @@ pub struct VcdWriter<W: io::Write + 'static> {
finished_init: bool,
timescale: SimDuration,
properties: VcdWriterProperties,
trace_as_string_buf: String,
}
impl<W: io::Write + 'static> VcdWriter<W> {
@ -1326,6 +1381,21 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
.built_scalar_id_to_vcd_id(first_id + element_index),
)?
}
MemoryElementPartBody::TraceAsString { ty } => {
self.trace_as_string_buf.clear();
ty.trace_fmt_append_to_string(
&mut self.trace_as_string_buf,
OpaqueSimValueSlice::from_bitslice(&element_data[start..start + len]),
);
write_string_value_change(
&mut self.writer,
&self.trace_as_string_buf,
self.properties
.scalar_id_to_vcd_id_map
.built_scalar_id_to_vcd_id(first_id + element_index),
)?;
self.trace_as_string_buf.clear();
}
}
}
Ok(())
@ -1419,6 +1489,16 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
.built_scalar_id_to_vcd_id(id.as_usize()),
)
}
fn set_signal_string(&mut self, id: TraceScalarId, value: &str) -> Result<(), Self::Error> {
write_string_value_change(
&mut self.writer,
value,
self.properties
.scalar_id_to_vcd_id_map
.built_scalar_id_to_vcd_id(id.as_usize()),
)
}
}
impl<W: io::Write> fmt::Debug for VcdWriter<W> {
@ -1428,6 +1508,7 @@ impl<W: io::Write> fmt::Debug for VcdWriter<W> {
finished_init,
timescale,
properties: _,
trace_as_string_buf: _,
} = self;
f.debug_struct("VcdWriter")
.field("finished_init", finished_init)

View file

@ -12,11 +12,13 @@ use crate::{
bundle::BundleType,
firrtl::ExportOptions,
module::Module,
util::HashMap,
sim::{Simulation, vcd::VcdWriterDecls},
util::{HashMap, RcWriter},
};
use serde::{Deserialize, Serialize};
use std::{
fmt::{self, Write},
panic::Location,
path::{Path, PathBuf},
process::Command,
sync::{Mutex, OnceLock},
@ -222,3 +224,190 @@ pub fn assert_formal<M: AsRef<Module<T>>, T: BundleType>(
)
.expect("testing::assert_formal() failed");
}
pub struct CheckedVcdOutput {
writer: Option<RcWriter>,
expected_path: PathBuf,
expected_contents: Result<String, (Option<PathBuf>, std::io::Error)>,
location: &'static Location<'static>,
}
impl CheckedVcdOutput {
#[must_use]
#[track_caller]
pub fn new<T: BundleType>(sim: &mut Simulation<T>, expected_path: PathBuf) -> Self {
let writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
Self {
writer: Some(writer),
expected_contents: std::fs::read_to_string(&expected_path).map_err(|e| {
eprintln!(
"error: failed to read expected VCD from: {}",
expected_path.display(),
);
(std::env::current_dir().ok(), e)
}),
expected_path,
location: Location::caller(),
}
}
#[must_use]
#[track_caller]
#[doc(hidden)]
pub fn __checked_vcd_output_macro_helper<T: BundleType>(
sim: &mut Simulation<T>,
cargo_manifest_dir: &'static str,
path: &'static str,
) -> Self {
Self::new(sim, Path::new(cargo_manifest_dir).join(path))
}
pub fn with_vcd_output<R>(&self, f: impl FnOnce(&str) -> R) -> R {
let Some(writer) = &self.writer else {
unreachable!();
};
writer.clone().borrow(|output| {
let Ok(output) = str::from_utf8(output) else {
unreachable!("VcdWriter writes valid UTF-8");
};
f(output)
})
}
#[track_caller]
pub fn finish(mut self) {
let Ok(()) = self.finish_impl(|msg| panic!("{msg}"));
}
fn finish_impl<E>(
&mut self,
error: impl FnOnce(std::fmt::Arguments<'_>) -> E,
) -> Result<(), E> {
let Self {
writer: Some(writer),
expected_path,
expected_contents,
location,
} = self
else {
// already finished
return Ok(());
};
let Ok(vcd) = String::from_utf8(writer.take()) else {
unreachable!("VcdWriter writes valid UTF-8");
};
let expected_path_d = expected_path.display();
if expected_contents
.as_ref()
.is_ok_and(|expected_contents| *expected_contents == vcd)
{
// avoid written output from being split from threads interleaving writes to stdout
let _stdout = std::io::stderr().lock();
// use println to get output captured by tests
println!("\n{location}: generated VCD matches the expected VCD in {expected_path_d}");
return Ok(());
}
// avoid written output from being split from threads interleaving writes to stderr
let _stderr = std::io::stderr().lock();
let error = |msg: std::fmt::Arguments<'_>| {
// print msg at both beginning and end so it's easier to find when the vcd is huge
Err(error(format_args!(
"\n{msg}####### VCD:\n{vcd}\n#######\n{msg}"
)))
};
let error = |msg: std::fmt::Arguments<'_>| match &*expected_contents {
Ok(_) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
{msg}",
)),
Err((Some(current_dir), e)) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
error: failed to read: {e}\n\
current dir: {current_dir}\n\
{msg}",
current_dir = current_dir.display(),
)),
Err((None, e)) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
error: failed to read: {e}\n\
{msg}",
)),
};
const OVERWRITE_VAR_NAME: &str = "OVERWRITE_EXPECTED_VCD";
const OVERWRITE_VAR_VALUE: &str = "overwrite";
match std::env::var_os(OVERWRITE_VAR_NAME) {
Some(v) if v == OVERWRITE_VAR_VALUE => match std::fs::write(&expected_path, &vcd) {
Ok(()) => error(format_args!(
"warning: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- writing the generated VCD to {expected_path_d}\n"
)),
Err(e) => error(format_args!(
"error: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- tried to write the generated VCD to {expected_path_d}\n\
error: failed to write: {e}"
)),
},
_ => error(format_args!(
"note: rerun the test with the environment variable `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}`\n\
to update the expected output to match the generated output.\n"
)),
}
}
}
impl Drop for CheckedVcdOutput {
#[track_caller]
fn drop(&mut self) {
let _ = self.finish_impl(|msg| {
if std::thread::panicking() {
eprintln!("{msg}"); // use eprintln to get output captured by tests
} else {
panic!("{msg}");
}
});
}
}
#[macro_export]
/// Use in tests to check that [`Simulation`] generates the expected VCD traces, by comparing to a `.vcd` file containing the expected traces.
///
/// Use like so:
/// ```
/// # use fayalite::prelude::*;
/// #
/// # #[hdl_module]
/// # fn my_module() {
/// # #[hdl]
/// # let a: UInt<8> = m.input();
/// # #[hdl]
/// # let b: UInt<8> = m.output();
/// # connect(b, 0u8);
/// # #[hdl]
/// # if a.cmp_eq(100u8) {
/// # connect(b, 42u8);
/// # }
/// # }
/// // inside your #[test] fn my_test():
///
/// // get the module to simulate:
/// let m = my_module();
/// // create a simulation of the module:
/// let mut sim = Simulation::new(m);
/// // set up the expected VCD traces, the given .vcd path is relative to env!("CARGO_MANIFEST_DIR")
/// let _checked_vcd_output = checked_vcd_output!(
/// &mut sim,
/// "tests/expected/my_test.vcd",
/// );
/// // now run the simulation like normal:
/// sim.write(sim.io().a, 0u8);
/// assert_eq!(sim.read(sim.io().b).as_int(), 0);
/// sim.advance_time(SimDuration::from_micros(1));
/// sim.write(sim.io().a, 100u8);
/// assert_eq!(sim.read(sim.io().b).as_int(), 42);
/// ```
macro_rules! checked_vcd_output {
($sim:expr, $path_relative_to_manifest_dir:expr $(,)?) => {
$crate::testing::CheckedVcdOutput::__checked_vcd_output_macro_helper(
$sim,
$crate::__std::env!("CARGO_MANIFEST_DIR"),
$crate::__std::concat!($path_relative_to_manifest_dir),
)
};
}
pub use checked_vcd_output;

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,8 @@ use crate::{
prelude::PhantomConst,
reset::{AsyncReset, Reset, SyncReset},
sim::value::DynSimOnly,
ty::{BaseType, CanonicalType},
ty::{BaseType, CanonicalType, TraceAsString, TraceAsStringTrait},
util::serde_by_id::SerdeById,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -38,6 +39,7 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst<
#[derive(Serialize, Deserialize)]
#[serde(rename = "CanonicalType")]
#[expect(private_interfaces)]
pub(crate) enum SerdeCanonicalType<
ArrayElement = CanonicalType,
ThePhantomConst = SerdePhantomConst<Interned<PhantomConstCanonicalValue>>,
@ -65,6 +67,10 @@ pub(crate) enum SerdeCanonicalType<
Clock,
PhantomConst(ThePhantomConst),
DynSimOnly(DynSimOnly),
TraceAsString {
inner_ty: Interned<CanonicalType>,
trace_as_string: SerdeById<Interned<dyn TraceAsStringTrait>>,
},
}
impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> {
@ -82,6 +88,7 @@ impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomCo
Self::Clock => "a Clock",
Self::PhantomConst(_) => "a PhantomConst",
Self::DynSimOnly(_) => "a SimOnlyValue",
Self::TraceAsString { .. } => "a TraceAsString",
}
}
}
@ -109,6 +116,15 @@ impl<T: BaseType> From<T> for SerdeCanonicalType {
CanonicalType::Clock(Clock {}) => Self::Clock,
CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())),
CanonicalType::DynSimOnly(ty) => Self::DynSimOnly(ty),
CanonicalType::TraceAsString(TraceAsString {
inner_ty,
trace_as_string,
}) => Self::TraceAsString {
inner_ty: inner_ty.interned(),
trace_as_string: SerdeById {
inner: trace_as_string.interned(),
},
},
}
}
}
@ -130,6 +146,13 @@ impl From<SerdeCanonicalType> for CanonicalType {
Self::PhantomConst(PhantomConst::new_interned(value.0))
}
SerdeCanonicalType::DynSimOnly(value) => Self::DynSimOnly(value),
SerdeCanonicalType::TraceAsString {
inner_ty,
trace_as_string,
} => Self::TraceAsString(TraceAsString {
inner_ty: crate::intern::LazyInterned::Interned(inner_ty),
trace_as_string: crate::intern::LazyInterned::Interned(trace_as_string.inner),
}),
}
}
}

View file

@ -46,3 +46,4 @@ pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice}
pub mod job_server;
pub mod prefix_sum;
pub mod ready_valid;
pub(crate) mod serde_by_id;

View file

@ -241,15 +241,13 @@ mod tests {
/// happens to be in phase with the offending input or output).
#[hdl_module]
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
#[hdl]
let clk: Clock = m.input();
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk,
clk: formal_global_clock(),
rst: formal_reset().to_reset(),
},
);
@ -280,7 +278,7 @@ mod tests {
#[hdl]
let index_to_check = wire(index_ty);
connect(index_to_check, any_const(index_ty));
hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), "");
hdl_assume(cd.clk, index_to_check.cmp_lt(capacity.get()), "");
// instantiate and connect the queue
#[hdl]
@ -300,13 +298,13 @@ mod tests {
let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero());
#[hdl]
if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) {
hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), "");
hdl_assert(cd.clk, expected_count_reg.cmp_ne(capacity.get()), "");
connect_any(expected_count_reg, expected_count_reg + 1u8);
} else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) {
hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
hdl_assert(cd.clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
connect_any(expected_count_reg, expected_count_reg - 1u8);
}
hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), "");
hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), "");
// keep an independent write index into the FIFO's circular buffer
#[hdl]
@ -374,7 +372,7 @@ mod tests {
match inp_firing_data {
// ... and we are not receiving data, then we must not
// transmit any data.
HdlNone => hdl_assert(clk, HdlOption::is_none(out_firing_data), ""),
HdlNone => hdl_assert(cd.clk, HdlOption::is_none(out_firing_data), ""),
// If we are indeed receiving some data...
HdlSome(data_in) => {
#[hdl]
@ -382,7 +380,9 @@ mod tests {
// ... and transmitting at the same time, we
// must be transmitting the input data itself,
// since the holding register is empty.
HdlSome(data_out) => hdl_assert(clk, data_out.cmp_eq(data_in), ""),
HdlSome(data_out) => {
hdl_assert(cd.clk, data_out.cmp_eq(data_in), "")
}
// If we are receiving, but not transmitting,
// store the received data in the holding
// register.
@ -397,11 +397,11 @@ mod tests {
match out_firing_data {
// ... and we are not transmitting it, we cannot
// receive any more data.
HdlNone => hdl_assert(clk, HdlOption::is_none(inp_firing_data), ""),
HdlNone => hdl_assert(cd.clk, HdlOption::is_none(inp_firing_data), ""),
// If we are transmitting a previously stored value...
HdlSome(data_out) => {
// ... it must be the same data we stored earlier.
hdl_assert(clk, data_out.cmp_eq(stored), "");
hdl_assert(cd.clk, data_out.cmp_eq(stored), "");
// Also, accept new data, if any. Otherwise,
// let the holding register become empty.
connect(stored_reg, inp_firing_data);
@ -417,17 +417,17 @@ mod tests {
connect(dut.dbg.index_to_check, index_to_check);
#[hdl]
if let HdlSome(stored) = stored_reg {
hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), "");
hdl_assert(cd.clk, stored.cmp_eq(dut.dbg.stored), "");
}
// sync the read and write indices
hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
hdl_assert(clk, out_index_reg.cmp_eq(dut.dbg.out_index), "");
hdl_assert(cd.clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
hdl_assert(cd.clk, out_index_reg.cmp_eq(dut.dbg.out_index), "");
// the indices should never go past the capacity, but induction
// doesn't know that...
hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(clk, out_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(cd.clk, inp_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(cd.clk, out_index_reg.cmp_lt(capacity.get()), "");
// strongly constrain the state of the holding register
//
@ -455,7 +455,7 @@ mod tests {
connect(expected_stored, pending_reads.cmp_lt(dut.count));
// sync with the state of the holding register
hdl_assert(
clk,
cd.clk,
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
"",
);

View file

@ -0,0 +1,234 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::util::HashMap;
use hashbrown::hash_map::Entry;
use serde::{Deserialize, Serialize, de::Error};
use std::{
any::TypeId,
borrow::Cow,
fmt::Write,
hash::{BuildHasher, Hash, Hasher},
marker::PhantomData,
sync::Mutex,
};
pub(crate) struct SerdeByIdProperties<T: SerdeByIdTrait> {
type_id: TypeId,
type_name: &'static str,
_phantom: PhantomData<fn(T) -> T>,
}
impl<T: SerdeByIdTrait> Clone for SerdeByIdProperties<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: SerdeByIdTrait> Copy for SerdeByIdProperties<T> {}
impl<T: SerdeByIdTrait> SerdeByIdProperties<T> {
pub fn of<U: ?Sized + 'static>() -> Self {
Self {
type_id: TypeId::of::<U>(),
type_name: std::any::type_name::<U>(),
_phantom: PhantomData,
}
}
}
pub(crate) trait SerdeByIdTrait: Hash + Eq + Clone + 'static + Send {
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Self>;
fn static_table() -> &'static SerdeByIdTable<Self>;
const NAME: &'static str;
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct SerdeRandomId([u32; 4]);
#[derive(Serialize, Deserialize)]
pub(crate) struct SerdeId<'a, T: SerdeByIdTrait> {
random_id: SerdeRandomId,
#[serde(borrow)]
type_name: Cow<'a, str>,
#[serde(skip)]
_phantom: PhantomData<fn(T) -> T>,
}
impl<'a, T: SerdeByIdTrait> Clone for SerdeId<'a, T> {
fn clone(&self) -> Self {
Self {
random_id: self.random_id,
type_name: self.type_name.clone(),
_phantom: PhantomData,
}
}
}
impl<'a, T: SerdeByIdTrait> Eq for SerdeId<'a, T> {}
impl<'a, 'b, T: SerdeByIdTrait> PartialEq<SerdeId<'b, T>> for SerdeId<'a, T> {
fn eq(&self, other: &SerdeId<'b, T>) -> bool {
let Self {
random_id,
type_name,
_phantom: _,
} = self;
*random_id == other.random_id && *type_name == other.type_name
}
}
impl<'a, T: SerdeByIdTrait> Hash for SerdeId<'a, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let Self {
random_id,
type_name: _,
_phantom: _,
} = self;
random_id.hash(state);
}
}
struct SerdeByIdTableRest<T: SerdeByIdTrait> {
from_serde: HashMap<SerdeId<'static, T>, T>,
serde_id_random_state: std::hash::RandomState,
buffer: String,
}
impl<T: SerdeByIdTrait> Default for SerdeByIdTableRest<T> {
fn default() -> Self {
Self {
from_serde: Default::default(),
serde_id_random_state: Default::default(),
buffer: Default::default(),
}
}
}
impl<T: SerdeByIdTrait> SerdeByIdTableRest<T> {
fn add_new(&mut self, value: T) -> SerdeId<'static, T> {
let properties = value.serde_by_id_properties();
let mut try_number = 0u64;
let mut hasher = self.serde_id_random_state.build_hasher();
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
write!(self.buffer, "{:?}", properties.type_id).expect("shouldn't ever fail");
self.buffer.hash(&mut hasher);
loop {
let mut hasher = hasher.clone();
try_number.hash(&mut hasher);
try_number += 1;
let key = SerdeId {
random_id: SerdeRandomId(std::array::from_fn(|i| {
let mut hasher = hasher.clone();
i.hash(&mut hasher);
hasher.finish() as u32
})),
type_name: Cow::Borrowed(properties.type_name),
_phantom: PhantomData,
};
match self.from_serde.entry(key) {
Entry::Occupied(_) => continue,
Entry::Vacant(e) => {
let key = e.key().clone();
e.insert(value);
return key;
}
}
}
}
}
pub(crate) struct SerdeByIdTableMut<T: SerdeByIdTrait> {
to_serde: HashMap<T, SerdeId<'static, T>>,
rest: SerdeByIdTableRest<T>,
}
impl<T: SerdeByIdTrait> Default for SerdeByIdTableMut<T> {
fn default() -> Self {
Self {
to_serde: Default::default(),
rest: Default::default(),
}
}
}
impl<T: SerdeByIdTrait> SerdeByIdTableMut<T> {
pub(crate) fn to_serde(&mut self, value: &T) -> SerdeId<'static, T> {
if let Some(retval) = self.to_serde.get(value) {
return retval.clone();
}
self.to_serde_insert(value)
}
#[cold]
fn to_serde_insert(&mut self, value: &T) -> SerdeId<'static, T> {
let value = value.clone();
let retval = self.rest.add_new(value.clone());
self.to_serde.insert(value, retval.clone());
retval
}
pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option<T> {
self.rest.from_serde.get(id).cloned()
}
}
pub(crate) struct SerdeByIdTable<T: SerdeByIdTrait>(Mutex<Option<SerdeByIdTableMut<T>>>);
impl<T: SerdeByIdTrait> SerdeByIdTable<T> {
pub(crate) const fn new() -> Self {
Self(Mutex::new(None))
}
pub(crate) fn to_serde(&self, value: &T) -> SerdeId<'static, T> {
self.0
.lock()
.expect("shouldn't be poison")
.get_or_insert_with(
#[cold]
|| Default::default(),
)
.to_serde(value)
}
pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option<T> {
self.0
.lock()
.expect("shouldn't be poison")
.get_or_insert_with(
#[cold]
|| Default::default(),
)
.from_serde(id)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, Ord, PartialOrd)]
pub(crate) struct SerdeById<T: SerdeByIdTrait> {
pub(crate) inner: T,
}
impl<'de, T: SerdeByIdTrait> Deserialize<'de> for SerdeById<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let id = SerdeId::deserialize(deserializer)?;
let inner = T::static_table().from_serde(&id).ok_or_else(|| {
D::Error::custom(format_args!(
"doesn't match any {} that was serialized this time this program was run: type_name={:?}",
T::NAME,
id.type_name,
))
})?;
Ok(Self { inner })
}
}
impl<T: SerdeByIdTrait> Serialize for SerdeById<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
T::static_table()
.to_serde(&self.inner)
.serialize(serializer)
}
}

View file

@ -546,7 +546,7 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
base.source_location(),
)? {},
}
match base.canonical_ty() {
match base.canonical_ty().unwrap_transparent_types() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -563,6 +563,9 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
v,
base.source_location(),
)? {},
CanonicalType::TraceAsString(_) => {
unreachable!("handled by unwrap_transparent_types")
}
}
self.required_dont_touch_targets.insert(target);
match v {
@ -592,6 +595,9 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
v,
instance.source_location(),
)? {},
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
unreachable!("base.is_valid_annotation_target() is known to be false")
}
}
}
}

View file

@ -58,11 +58,13 @@ impl<T: Type> Wire<T> {
ty: T::from_canonical(ty),
}
}
#[track_caller]
pub fn new_unchecked(
scoped_name: ScopedNameId,
source_location: SourceLocation,
ty: T,
) -> Self {
scoped_name.0.assert_is_name_id();
Self {
name: scoped_name,
source_location,
@ -76,7 +78,7 @@ impl<T: Type> Wire<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0
self.name.0.unwrap_name_id()
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

View file

@ -0,0 +1,6 @@
<!--
SPDX-License-Identifier: LGPL-3.0-or-later
See Notices.txt for copyright information
-->
`my_test.vcd` is used in the doctest of `fayalite::testing::checked_vcd_output`

View file

@ -0,0 +1,13 @@
$timescale 1 ps $end
$scope module my_module $end
$var wire 8 gAF7X a $end
$var wire 8 QS=a/ b $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 gAF7X
b0 QS=a/
$end
#1000000
b1100100 gAF7X
b101010 QS=a/

View file

@ -709,44 +709,35 @@ circuit check_enum_cmp_eq:
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
match lhs: @[module-XXXXXXXXXX.rs 5:1]
wire _cast_enum_to_bits_expr: UInt<10>
match lhs:
A:
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
B(_match_arm_value):
skip
C(_match_arm_value_1):
skip
B(_match_arm_value_2):
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B(_match_arm_value_3):
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
C(_match_arm_value_4):
skip
C(_match_arm_value_5):
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B(_match_arm_value_6):
skip
C(_match_arm_value_7):
wire _array_literal_expr: UInt<1>[3]
connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2])
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
connect _cast_enum_to_bits_expr, UInt<10>(0)
B(_cast_enum_to_bits_expr_B):
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
C(_cast_enum_to_bits_expr_C):
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
wire _cast_enum_to_bits_expr_1: UInt<10>
match rhs:
A:
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
B(_cast_enum_to_bits_expr_B_1):
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
C(_cast_enum_to_bits_expr_C_1):
wire _cast_array_to_bits_expr_1: UInt<1>[3]
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
wire _cast_to_bits_expr_1: UInt<3>
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -764,92 +755,53 @@ circuit check_enum_cmp_eq:
input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
match lhs.tag: @[module-XXXXXXXXXX.rs 5:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
wire _cast_enum_to_bits_expr: UInt<2>
match lhs.tag:
A:
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
B:
skip
C:
skip
connect _cast_enum_to_bits_expr, UInt<2>(0)
B:
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B:
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
C:
skip
connect _cast_enum_to_bits_expr, UInt<2>(1)
C:
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B:
skip
C:
wire _array_literal_expr: UInt<1>[3]
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
connect _cast_enum_to_bits_expr, UInt<2>(2)
wire _cast_enum_to_bits_expr_1: UInt<2>
match rhs.tag:
A:
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
B:
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
C:
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
A:
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
B:
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
C:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -866,83 +818,36 @@ circuit check_enum_cmp_eq:
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else:
wire _array_literal_expr: UInt<1>[3]
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
else:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -958,83 +863,36 @@ circuit check_enum_cmp_eq:
input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else:
wire _array_literal_expr: UInt<1>[3]
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
else:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
}
@ -3779,20 +3637,176 @@ circuit check_formal: %[[
input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1]
input pred3: UInt<1> @[module-XXXXXXXXXX.rs 8:1]
inst formal_reset of formal_reset @[formal.rs 185:24]
inst formal_reset of formal_reset @[builtin 1:1]
assert(clk, pred1, and(en1, not(formal_reset.rst)), "en check 1") @[module-XXXXXXXXXX.rs 9:1]
inst formal_reset_1 of formal_reset @[formal.rs 185:24]
assume(clk, pred2, and(en2, not(formal_reset_1.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1]
inst formal_reset_2 of formal_reset @[formal.rs 185:24]
cover(clk, pred3, and(en3, not(formal_reset_2.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1]
inst formal_reset_3 of formal_reset @[formal.rs 185:24]
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset_3.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
inst formal_reset_4 of formal_reset @[formal.rs 185:24]
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset_4.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
inst formal_reset_5 of formal_reset @[formal.rs 185:24]
cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset_5.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1]
extmodule formal_reset: @[formal.rs 169:5]
output rst: UInt<1> @[formal.rs 172:32]
assume(clk, pred2, and(en2, not(formal_reset.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1]
cover(clk, pred3, and(en3, not(formal_reset.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1]
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1]
extmodule formal_reset: @[builtin 1:1]
output rst: UInt<1> @[builtin 1:1]
defname = __fayalite_formal_reset
"#,
};
}
#[hdl_module(outline_generated)]
pub fn check_formal_input() {
#[hdl]
let bool_in: Bool = m.input();
#[hdl]
let bool_out: Bool = m.output();
#[hdl]
let any_const_out1: Bool = m.output();
#[hdl]
let any_const_out2: UInt<16> = m.output();
#[hdl]
let any_const_out3: SInt<12> = m.output();
#[hdl]
let any_seq_out: UInt<10> = m.output();
#[hdl]
let all_const_out: UInt<10> = m.output();
#[hdl]
let all_seq_out: UInt<10> = m.output();
#[hdl]
let bool_reg = reg_builder()
.clock_domain(
#[hdl]
ClockDomain {
clk: formal_global_clock(),
rst: formal_reset(),
},
)
.reset(false);
connect(bool_reg, bool_in);
connect(bool_out, bool_reg);
connect(any_const_out1, any_const(StaticType::TYPE));
connect(any_const_out2, any_const(StaticType::TYPE));
connect(any_const_out3, any_const(StaticType::TYPE));
connect(any_seq_out, any_seq(StaticType::TYPE));
connect(all_const_out, all_const(StaticType::TYPE));
connect(all_seq_out, all_seq(StaticType::TYPE));
}
#[test]
fn test_formal_input() {
let _n = SourceLocation::normalize_files_for_tests();
let m = check_formal_input();
dbg!(m);
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
"/test/check_formal_input.fir": r#"FIRRTL version 3.2.0
circuit check_formal_input: %[[
{
"class": "firrtl.AttributeAnnotation",
"description": "gclk",
"target": "~check_formal_input|check_formal_input>formal_global_clock"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>formal_global_clock"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const_1"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const_1"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const_2"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const_2"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyseq",
"target": "~check_formal_input|check_formal_input>any_seq"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_seq"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "allconst",
"target": "~check_formal_input|check_formal_input>all_const"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>all_const"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "allseq",
"target": "~check_formal_input|check_formal_input>all_seq"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>all_seq"
},
{
"class": "firrtl.transforms.BlackBoxInlineAnno",
"name": "fayalite_formal_reset.v",
"text": "module __fayalite_formal_reset(output rst);\n assign rst = $initstate;\nendmodule\n",
"target": "~check_formal_input|formal_reset"
}
]]
type Ty0 = {clk: Clock, rst: UInt<1>}
type Ty1 = {rst: UInt<1>}
module check_formal_input: @[module-XXXXXXXXXX.rs 1:1]
input bool_in: UInt<1> @[module-XXXXXXXXXX.rs 2:1]
output bool_out: UInt<1> @[module-XXXXXXXXXX.rs 3:1]
output any_const_out1: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
output any_const_out2: UInt<16> @[module-XXXXXXXXXX.rs 5:1]
output any_const_out3: SInt<12> @[module-XXXXXXXXXX.rs 6:1]
output any_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 7:1]
output all_const_out: UInt<10> @[module-XXXXXXXXXX.rs 8:1]
output all_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_1: Ty0
connect _bundle_literal_expr_1.clk, asClock(UInt<1>(0h0))
connect _bundle_literal_expr_1.rst, UInt<1>(0h0)
reg formal_global_clock: UInt<1>, _bundle_literal_expr_1.clk @[builtin 1:1]
inst formal_reset of formal_reset @[builtin 1:1]
reg any_const: UInt<1>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 13:1]
reg any_const_1: UInt<16>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 15:1]
reg any_const_2: SInt<12>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 17:1]
reg any_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 19:1]
reg all_const: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 21:1]
reg all_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 23:1]
wire _bundle_literal_expr: Ty0
connect _bundle_literal_expr.clk, asClock(formal_global_clock)
connect _bundle_literal_expr.rst, formal_reset.rst
regreset bool_reg: UInt<1>, _bundle_literal_expr.clk, _bundle_literal_expr.rst, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 10:1]
connect bool_reg, bool_in @[module-XXXXXXXXXX.rs 11:1]
connect bool_out, bool_reg @[module-XXXXXXXXXX.rs 12:1]
connect any_const_out1, any_const @[module-XXXXXXXXXX.rs 14:1]
connect any_const_out2, any_const_1 @[module-XXXXXXXXXX.rs 16:1]
connect any_const_out3, any_const_2 @[module-XXXXXXXXXX.rs 18:1]
connect any_seq_out, any_seq @[module-XXXXXXXXXX.rs 20:1]
connect all_const_out, all_const @[module-XXXXXXXXXX.rs 22:1]
connect all_seq_out, all_seq @[module-XXXXXXXXXX.rs 24:1]
extmodule formal_reset: @[builtin 1:1]
output rst: UInt<1> @[builtin 1:1]
defname = __fayalite_formal_reset
"#,
};
@ -3925,21 +3939,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
HdlSome:
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty5
wire _cast_bits_to_bundle_expr_flattened_1: Ty6
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0)
wire _cast_bits_to_enum_expr_1: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)):
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1
connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
; connect different types:
; lhs: SInt<1>
; rhs: SInt<2>
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_2: Ty4
connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome)
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
@ -3961,18 +3964,18 @@ circuit check_enum_connect_any:
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
C:
wire __connect_variant_body_3: Ty8 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_2: Ty8
wire _cast_bits_to_bundle_expr_flattened_2: Ty9
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_2: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_1: Ty8
wire _cast_bits_to_bundle_expr_flattened_1: Ty9
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_1: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)):
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1]
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_4: Ty1
connect _bundle_literal_expr_4.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_1: Ty9
@ -4001,18 +4004,18 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
B:
wire __connect_variant_body_5: Ty5 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty4
wire _cast_bits_to_bundle_expr_flattened_3: Ty7
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_3: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_2: Ty4
wire _cast_bits_to_bundle_expr_flattened_2: Ty7
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_2: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
match _cast_bits_to_bundle_expr_3.tag: @[module-XXXXXXXXXX.rs 9:1]
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
match _cast_bits_to_bundle_expr_2.tag: @[module-XXXXXXXXXX.rs 9:1]
HdlNone:
wire _bundle_literal_expr_6: Ty5
connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone)
@ -4020,21 +4023,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
HdlSome:
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_4: Ty4
wire _cast_bits_to_bundle_expr_flattened_4: Ty7
connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_4: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_4.tag, 0)):
connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_enum_expr_4
connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body
; connect different types:
; lhs: SInt<2>
; rhs: SInt<1>
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_7: Ty5
connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome)
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
@ -4056,18 +4048,18 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
C:
wire __connect_variant_body_7: Ty8 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_5: Ty8
wire _cast_bits_to_bundle_expr_flattened_5: Ty9
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_5: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)):
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_3: Ty8
wire _cast_bits_to_bundle_expr_flattened_3: Ty9
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_3: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_5
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1]
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_9: Ty2
connect _bundle_literal_expr_9.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_3: Ty9
@ -4134,16 +4126,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
else:
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty3
wire _cast_bits_to_bundle_expr_flattened_1: Ty3
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag
connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
; connect different types:
; lhs: SInt<1>
; rhs: SInt<2>
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_2: Ty2
connect _bundle_literal_expr_2.tag, UInt<1>(0h1)
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
@ -4159,13 +4145,13 @@ circuit check_enum_connect_any:
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
else:
wire __connect_variant_body_3: Ty4 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_2: Ty4
wire _cast_bits_to_bundle_expr_flattened_2: Ty4
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty4
wire _cast_bits_to_bundle_expr_flattened_1: Ty4
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_4: Ty0
connect _bundle_literal_expr_4.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_1: Ty4
@ -4187,29 +4173,23 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
else when eq(i1.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 9:1]
wire __connect_variant_body_5: Ty3 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty2
wire _cast_bits_to_bundle_expr_flattened_3: Ty2
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
when eq(_cast_bits_to_bundle_expr_3.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_2: Ty2
wire _cast_bits_to_bundle_expr_flattened_2: Ty2
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag
connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
when eq(_cast_bits_to_bundle_expr_2.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_6: Ty3
connect _bundle_literal_expr_6.tag, UInt<1>(0h0)
connect _bundle_literal_expr_6.body, UInt<2>(0h0)
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
else:
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_4: Ty2
wire _cast_bits_to_bundle_expr_flattened_4: Ty2
connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_bundle_expr_flattened_4.tag
connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body
; connect different types:
; lhs: SInt<2>
; rhs: SInt<1>
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_7: Ty3
connect _bundle_literal_expr_7.tag, UInt<1>(0h1)
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
@ -4225,13 +4205,13 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
else:
wire __connect_variant_body_7: Ty4 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_5: Ty4
wire _cast_bits_to_bundle_expr_flattened_5: Ty4
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty4
wire _cast_bits_to_bundle_expr_flattened_3: Ty4
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_9: Ty1
connect _bundle_literal_expr_9.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_3: Ty4
@ -4905,12 +4885,14 @@ circuit check_struct_cmp_eq:
wire _cast_to_bits_expr_1: UInt<3>
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1]
connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1]
connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1]
wire _bundle_structural_eq: UInt<1>
connect _bundle_structural_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b))
connect test_struct_cmp_eq, _bundle_structural_eq @[module-XXXXXXXXXX.rs 11:1]
connect test_struct_cmp_ne, not(_bundle_structural_eq) @[module-XXXXXXXXXX.rs 13:1]
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1]
connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19:1]
connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1]
",
};
}

View file

@ -1,15 +1,28 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use bitvec::{order::Lsb0, view::BitView};
use fayalite::{
memory::{ReadStruct, ReadWriteStruct, WriteStruct},
module::{instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc},
assert_export_firrtl,
firrtl::ExportOptions,
formal::FormalInputKind,
memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask},
module::{
instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc,
transform::simplify_enums::SimplifyEnumsKind,
},
prelude::*,
reset::ResetType,
sim::vcd::VcdWriterDecls,
ty::SimValueDebug,
util::{RcWriter, ready_valid::queue},
};
use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc};
use std::{
collections::BTreeMap,
num::NonZeroUsize,
panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
rc::Rc,
};
#[hdl_module(outline_generated)]
pub fn connect_const() {
@ -2985,3 +2998,754 @@ fn test_queue_4_true_true() {
include_str!("sim/expected/queue_4_true_true.txt"),
);
}
#[hdl(outline_generated, custom_debug(sim), cmp_eq)]
pub enum HasCustomDebug {
Text(UInt<512>),
FmtError,
}
impl HasCustomDebug {
#[hdl]
pub fn new_sim(text: Result<&str, std::fmt::Error>) -> SimValue<Self> {
match text {
Ok(text) => {
let mut retval = HasCustomDebug.Text.zero();
let src = text.as_bytes().view_bits::<Lsb0>();
let dest = retval.bits_mut();
let len = src.len().min(dest.len());
dest[..len].clone_from_bitslice(&src[..len]);
#[hdl(sim)]
HasCustomDebug.Text(retval)
}
Err(std::fmt::Error) =>
{
#[hdl(sim)]
HasCustomDebug.FmtError()
}
}
}
pub fn new(text: Result<&str, std::fmt::Error>) -> Expr<Self> {
Self::new_sim(text).to_expr()
}
}
impl SimValueDebug for HasCustomDebug {
#[hdl]
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
if f.alternate() {
return #[hdl(sim)]
match value {
Self::FmtError => f.write_str("FmtError"),
Self::Text(text) => f.debug_tuple("Text").field(text).finish(),
};
}
#[hdl(sim)]
match value {
Self::FmtError => Err(std::fmt::Error),
Self::Text(text) => {
assert_eq!(text.ty().width() % u8::BITS as usize, 0);
let mut bytes = vec![0u8; text.ty().width() / u8::BITS as usize];
bytes
.view_bits_mut::<Lsb0>()
.clone_from_bitslice(text.bits());
if let Some(len) = bytes.iter().position(|b| *b == 0) {
bytes.truncate(len);
}
f.write_str(&String::from_utf8_lossy(&bytes))
}
}
}
}
#[hdl_module(outline_generated)]
pub fn sim_trace_as_string() {
#[hdl]
let clk: Clock = m.input();
#[hdl]
let read: ReadStruct<TraceAsString<Array<HasCustomDebug, 2>>, ConstUsize<8>> = m.input();
#[hdl]
let write: WriteStruct<Array<TraceAsString<HasCustomDebug>, 2>, ConstUsize<8>> = m.input();
#[hdl]
let mut mem = memory_with_init([[HasCustomDebug::new(Ok("")).to_trace_as_string(); 2]; 4]);
let read_port = mem.new_read_port();
connect(read_port.clk, clk);
connect_any(read_port.addr, read.addr);
connect(read_port.en, read.en);
for (l, r) in read.data.iter().zip(read_port.data.iter()) {
connect(l, &**r);
}
let write_port = mem.new_write_port();
connect(write_port.clk, clk);
connect_any(write_port.addr, write.addr);
connect(write_port.data, write.data);
connect(write_port.en, write.en);
connect(write_port.mask, write.mask);
}
#[hdl]
#[test]
fn test_sim_trace_as_string() {
let _n = SourceLocation::normalize_files_for_tests();
let m = sim_trace_as_string();
let mut sim = Simulation::new(m);
// sim.set_breakpoints_unstable(Default::default(), true);
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write(sim.io().clk, false);
sim.write(sim.io().read.clk, false);
sim.write(sim.io().write.clk, false);
#[derive(Debug)]
struct TestCase {
read: Option<(u8, [Result<&'static str, std::fmt::Error>; 2])>,
write_addr: Option<u8>,
write_data: [Result<&'static str, std::fmt::Error>; 2],
write_mask: [bool; 2],
}
const TEST_CASES: &[TestCase] = &[
TestCase {
read: None,
write_addr: None,
write_data: [Ok(""); 2],
write_mask: [false; 2],
},
TestCase {
read: None,
write_addr: Some(0),
write_data: [Ok("mem[0][0]"), Ok("mem[0][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(1),
write_data: [Ok("mem[1][0]"), Ok("mem[1][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(2),
write_data: [Ok("mem[2][0]"), Ok("mem[2][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(3),
write_data: [Ok("mem[3][0]"), Ok("mem[3][1]")],
write_mask: [true; 2],
},
TestCase {
read: Some((1, [Ok("mem[1][0]"), Ok("mem[1][1]")])),
write_addr: None,
write_data: [Err(std::fmt::Error), Err(std::fmt::Error)],
write_mask: [true; 2],
},
TestCase {
read: Some((1, [Err(std::fmt::Error), Err(std::fmt::Error)])),
write_addr: Some(1),
write_data: [Err(std::fmt::Error), Err(std::fmt::Error)],
write_mask: [true; 2],
},
];
for test_case in TEST_CASES {
let TestCase {
read,
write_addr,
write_data,
write_mask,
} = test_case;
sim.write(sim.io().read.addr, read.map(|v| v.0).unwrap_or(0));
sim.write(sim.io().read.en, read.is_some());
sim.write(sim.io().write.addr, write_addr.unwrap_or(0));
sim.write(sim.io().write.en, write_addr.is_some());
sim.write(
sim.io().write.data,
write_data.map(|v| HasCustomDebug::new_sim(v).to_trace_as_string()),
);
sim.write(
sim.io().write.mask,
write_mask.map(|v| splat_mask(TraceAsString[HasCustomDebug], v.to_expr())),
);
sim.write(sim.io().clk, false);
sim.advance_time(SimDuration::from_nanos(500));
sim.write(sim.io().clk, true);
sim.advance_time(SimDuration::from_nanos(500));
if let Some((_, expected_read_data)) = read {
let read_data = sim.read(sim.io().read.data);
let expected_read_data = expected_read_data
.map(HasCustomDebug::new_sim)
.into_sim_value();
assert!(
*read_data.inner() == expected_read_data,
"{read_data:#?}\n!= {expected_read_data:#?}",
);
}
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/sim_trace_as_string.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/sim_trace_as_string.txt") {
panic!();
}
}
#[test]
fn test_firrtl_trace_as_string() {
let _n = SourceLocation::normalize_files_for_tests();
let m = sim_trace_as_string();
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: false,
simplify_enums: None,
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text: UInt<512>, FmtError|}
type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => Ty0[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect `mem`.w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect `mem`.w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect `mem`.w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect `mem`.w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: true,
simplify_enums: None,
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text: UInt<512>, FmtError|}
type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty5 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<513>[2]}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<513>[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<513>[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_r0: Ty3 @[module-XXXXXXXXXX.rs 6:1]
wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr: Ty0
wire _cast_bits_to_enum_expr_body: UInt<512>
connect _cast_bits_to_enum_expr_body, head(`mem`.r0.data[0], 512)
when eq(UInt<1>(0), tail(`mem`.r0.data[0], 512)):
connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body)
else:
connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(FmtError)
connect mem_r0.data[0], _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1]
wire _cast_bits_to_enum_expr_1: Ty0
wire _cast_bits_to_enum_expr_body_1: UInt<512>
connect _cast_bits_to_enum_expr_body_1, head(`mem`.r0.data[1], 512)
when eq(UInt<1>(0), tail(`mem`.r0.data[1], 512)):
connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body_1)
else:
connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(FmtError)
connect mem_r0.data[1], _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr: UInt<513>
match mem_w1.data[0]:
Text(_cast_enum_to_bits_expr_Text):
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_Text, UInt<1>(0)), 513)
FmtError:
connect _cast_enum_to_bits_expr, UInt<513>(1)
connect `mem`.w1.data[0], _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0], mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
wire _cast_enum_to_bits_expr_1: UInt<513>
match mem_w1.data[1]:
Text(_cast_enum_to_bits_expr_Text_1):
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_Text_1, UInt<1>(0)), 513)
FmtError:
connect _cast_enum_to_bits_expr_1, UInt<513>(1)
connect `mem`.w1.data[1], _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1], mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: false,
simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody),
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text, FmtError|}
type Ty1 = {tag: Ty0, body: UInt<512>}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty5 = {tag: UInt<1>, body: UInt<1>}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]}
type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => Ty1[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.data, mem_w1.data @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0].tag, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0].body, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1].tag, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1].body, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: true,
simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody),
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_0_tag.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_0_tag"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_0_body.mem",
"hexOrBinary": "h",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_0_body"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_1_tag.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_1_tag"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_1_body.mem",
"hexOrBinary": "h",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_1_body"
}
]]
type Ty0 = {|Text, FmtError|}
type Ty1 = {tag: Ty0, body: UInt<512>}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty5 = {tag: UInt<1>, body: UInt<1>}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]}
type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<1>}
type Ty8 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<1>, mask: UInt<1>}
type Ty9 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<512>}
type Ty10 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<512>, mask: UInt<1>}
type Ty11 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1]
mem mem_0_tag: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<1>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_0_body: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<512>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_1_tag: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<1>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_1_body: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<512>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_r0: Ty4 @[module-XXXXXXXXXX.rs 6:1]
wire mem_w1: Ty6 @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr: Ty0
when eq(UInt<1>(0), tail(mem_0_tag.r0.data, 0)):
connect _cast_bits_to_enum_expr, {|Text, FmtError|}(Text)
else:
connect _cast_bits_to_enum_expr, {|Text, FmtError|}(FmtError)
connect mem_r0.data[0].tag, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr: UInt<1>
match mem_w1.data[0].tag:
Text:
connect _cast_enum_to_bits_expr, UInt<1>(0)
FmtError:
connect _cast_enum_to_bits_expr, UInt<1>(1)
connect mem_0_tag.w1.data, _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.mask, mem_w1.mask[0].tag @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.data[0].body, mem_0_body.r0.data @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.w1.data, mem_w1.data[0].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.mask, mem_w1.mask[0].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr_1: Ty0
when eq(UInt<1>(0), tail(mem_1_tag.r0.data, 0)):
connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(Text)
else:
connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(FmtError)
connect mem_r0.data[1].tag, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr_1: UInt<1>
match mem_w1.data[1].tag:
Text:
connect _cast_enum_to_bits_expr_1, UInt<1>(0)
FmtError:
connect _cast_enum_to_bits_expr_1, UInt<1>(1)
connect mem_1_tag.w1.data, _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.mask, mem_w1.mask[1].tag @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.data[1].body, mem_1_body.r0.data @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.w1.data, mem_w1.data[1].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.mask, mem_w1.mask[1].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
wire mem_w1_1: Ty11 @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.addr, mem_w1_1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.en, mem_w1_1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.clk, mem_w1_1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.data, mem_w1_1.data @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[0].tag, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[0].body, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[1].tag, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[1].body, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1_1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1_1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1_1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1_1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1_1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem_0_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
"/test/sim_trace_as_string/mem_0_tag.mem": r"0
0
0
0
",
"/test/sim_trace_as_string/mem_1_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
"/test/sim_trace_as_string/mem_1_tag.mem": r"0
0
0
0
",
};
}
#[hdl_module(outline_generated)]
pub fn formal_counter(count_modulus: u8, asserted_max_count: u8) {
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk: formal_global_clock(),
rst: formal_reset(),
},
);
#[hdl]
let count_reg: UInt<8> = reg_builder().clock_domain(cd).reset(0u8);
let next_count = count_reg + 1u8;
#[hdl]
if next_count.cmp_lt(count_modulus) {
connect_any(count_reg, next_count);
} else {
connect(count_reg, 0u8);
}
#[hdl]
let count: UInt<8> = m.output();
connect(count, count_reg);
#[hdl]
let enable_assert: Bool = m.input();
#[hdl]
if enable_assert {
hdl_assert(cd.clk, count_reg.cmp_le(asserted_max_count), "");
}
#[hdl]
let any_seq_out: UInt<16> = m.output();
connect(any_seq_out, any_seq(any_seq_out.ty()));
}
#[hdl]
#[test]
fn test_formal_counter() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(formal_counter(10, 10));
let _checked_vcd_output =
checked_vcd_output!(&mut sim, "tests/sim/expected/test_formal_counter.vcd");
let Some((_, any_seq_in)) = sim
.global_io()
.into_iter()
.find(|(global, _)| global.kind() == FormalInputKind::AnySeq)
else {
panic!("can't find any_seq");
};
let any_seq_in = Expr::<UInt<16>>::from_canonical(any_seq_in);
sim.write_clock(formal_global_clock(), false);
sim.write_reset(formal_reset(), true);
sim.write(any_seq_in, 0u16);
sim.write(sim.io().enable_assert, true);
sim.advance_time(SimDuration::from_micros(1));
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 0u16);
sim.write_clock(formal_global_clock(), true);
sim.write(any_seq_in, 1234u16);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 1234u16);
assert_eq!(sim.read(sim.io().count).as_int(), 0);
sim.write_reset(formal_reset(), false);
sim.advance_time(SimDuration::from_micros(1));
for i in 0..32u8 {
assert_eq!(i % 10, sim.read(sim.io().count).as_int());
sim.write_clock(formal_global_clock(), false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(formal_global_clock(), true);
sim.advance_time(SimDuration::from_micros(1));
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/test_formal_counter.txt") {
panic!();
}
}
#[cfg(panic = "unwind")]
#[hdl]
#[test]
fn test_formal_counter_assert() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(formal_counter(10, 8));
let _checked_vcd_output = checked_vcd_output!(
&mut sim,
"tests/sim/expected/test_formal_counter_assert.vcd"
);
let Some((_, any_seq_in)) = sim
.global_io()
.into_iter()
.find(|(global, _)| global.kind() == FormalInputKind::AnySeq)
else {
panic!("can't find any_seq");
};
let any_seq_in = Expr::<UInt<16>>::from_canonical(any_seq_in);
let half_us = SimDuration::from_nanos(500);
sim.write_clock(formal_global_clock(), false);
sim.write_reset(formal_reset(), true);
sim.write(any_seq_in, 0u16);
sim.write(sim.io().enable_assert, false);
sim.advance_time(half_us);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 0u16);
sim.write_clock(formal_global_clock(), true);
sim.write(any_seq_in, 1234u16);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 1234u16);
assert_eq!(sim.read(sim.io().count).as_int(), 0);
sim.write_reset(formal_reset(), false);
sim.advance_time(half_us);
const PANIC_MSG: &str = "Assertions/Assumptions failed at time 20.500000000000 \u{3bc}s:\n\
at module-XXXXXXXXXX.rs:12:1: in InstantiatedModule(formal_counter: formal_counter): assert failed: \n";
const EXPECTED_FAILURE_CYCLE: u8 = 19;
for i in 0.. {
dbg!(i);
assert_eq!(i % 10, sim.read(sim.io().count).as_int());
sim.write(sim.io().enable_assert, i > 15);
sim.write_clock(formal_global_clock(), false);
sim.advance_time(half_us);
match catch_unwind(AssertUnwindSafe(|| {
sim.write_clock(formal_global_clock(), true);
sim.advance_time(half_us);
})) {
Ok(()) => assert!(i < EXPECTED_FAILURE_CYCLE),
Err(e) => match e.downcast::<String>() {
Ok(e) if *e == PANIC_MSG => {
assert_eq!(i, EXPECTED_FAILURE_CYCLE);
break;
}
Ok(e) => resume_unwind(e),
Err(e) => resume_unwind(e),
},
}
}
}

View file

@ -419,6 +419,7 @@ Simulation {
},
pc: 38,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -497,6 +498,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1759,5 +1761,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -76,6 +76,7 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -101,6 +102,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -186,5 +188,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -54,6 +54,7 @@ Simulation {
},
pc: 2,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -77,6 +78,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -138,5 +140,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -80,6 +80,7 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -106,6 +107,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -206,5 +208,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -180,6 +180,7 @@ Simulation {
},
pc: 19,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -216,6 +217,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -385,5 +387,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -162,6 +162,7 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -197,6 +198,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -366,5 +368,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -72,6 +72,7 @@ Simulation {
},
pc: 4,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -97,6 +98,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [],
uninitialized_ios: {},
@ -169,5 +171,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -409,6 +409,7 @@ Simulation {
},
pc: 45,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -465,6 +466,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -745,5 +747,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1184,6 +1184,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -1324,6 +1325,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1955,5 +1957,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -44,6 +44,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -67,6 +68,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -261,5 +263,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -416,5 +418,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -407,6 +407,7 @@ Simulation {
},
pc: 44,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -464,6 +465,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -705,5 +707,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -2728,6 +2728,7 @@ Simulation {
},
pc: 256,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -3183,6 +3184,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -7927,5 +7929,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -494,6 +494,7 @@ Simulation {
},
pc: 41,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -579,6 +580,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1650,5 +1652,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -526,6 +526,7 @@ Simulation {
},
pc: 52,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -607,6 +608,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1285,5 +1287,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1336,6 +1336,7 @@ Simulation {
},
pc: 129,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1495,6 +1496,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -3345,5 +3347,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -187,6 +187,7 @@ Simulation {
},
pc: 17,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -225,6 +226,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -577,5 +579,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -172,6 +172,7 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -215,6 +216,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -527,5 +529,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1083,6 +1083,7 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1201,6 +1202,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2160,5 +2162,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1064,6 +1064,7 @@ Simulation {
},
pc: 132,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1180,6 +1181,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2139,5 +2141,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1093,6 +1093,7 @@ Simulation {
},
pc: 136,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1211,6 +1212,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2170,5 +2172,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1074,6 +1074,7 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1190,6 +1191,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2149,5 +2151,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1098,6 +1098,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1219,6 +1220,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2178,5 +2180,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1079,6 +1079,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1198,6 +1199,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2157,5 +2159,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1108,6 +1108,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1229,6 +1230,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2188,5 +2190,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1089,6 +1089,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1208,6 +1209,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2167,5 +2169,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1125,6 +1125,7 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1248,6 +1249,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2187,5 +2189,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1106,6 +1106,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1227,6 +1228,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2166,5 +2168,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1135,6 +1135,7 @@ Simulation {
},
pc: 141,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1258,6 +1259,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2197,5 +2199,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1116,6 +1116,7 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1237,6 +1238,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2176,5 +2178,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1104,6 +1104,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1227,6 +1228,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2186,5 +2188,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1085,6 +1085,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1206,6 +1207,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2165,5 +2167,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1114,6 +1114,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1237,6 +1238,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2196,5 +2198,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1095,6 +1095,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1216,6 +1217,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2175,5 +2177,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -636,6 +636,7 @@ Simulation {
},
pc: 69,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -725,6 +726,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1790,5 +1792,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -254,6 +254,7 @@ Simulation {
},
pc: 34,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -293,6 +294,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -545,5 +547,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -60,6 +60,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -87,6 +88,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -521,5 +523,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -60,6 +60,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -87,6 +88,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -521,5 +523,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -375,6 +375,7 @@ Simulation {
},
pc: 41,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -475,6 +476,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1768,5 +1770,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -512,6 +512,7 @@ Simulation {
},
pc: 57,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -591,6 +592,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -9726,5 +9728,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -539,5 +541,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -539,5 +541,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -497,5 +499,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -497,5 +499,6 @@ Simulation {
},
),
},
asserts: [],
..
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,221 @@
$timescale 1 ps $end
$scope module sim_trace_as_string $end
$var wire 1 J(7*b clk $end
$scope struct read $end
$var wire 8 @t0}\ addr $end
$var wire 1 78"T5 en $end
$var wire 1 G7v@m clk $end
$var string 1 F&^FN data $end
$upscope $end
$scope struct write $end
$var wire 8 "fUdW addr $end
$var wire 1 r1OK) en $end
$var wire 1 ,ADvU clk $end
$scope struct data $end
$var string 1 pD.mP \[0] $end
$var string 1 !V!em \[1] $end
$upscope $end
$scope struct mask $end
$var wire 1 l8dgD \[0] $end
$var wire 1 1/sDs \[1] $end
$upscope $end
$upscope $end
$scope struct mem $end
$scope struct contents $end
$scope struct \[0] $end
$scope struct mem $end
$var string 1 sz>#| \[0] $end
$var string 1 G._83 \[1] $end
$upscope $end
$upscope $end
$scope struct \[1] $end
$scope struct mem $end
$var string 1 2r3#W \[0] $end
$var string 1 AbGF% \[1] $end
$upscope $end
$upscope $end
$scope struct \[2] $end
$scope struct mem $end
$var string 1 .^<$p \[0] $end
$var string 1 ?s@Dc \[1] $end
$upscope $end
$upscope $end
$scope struct \[3] $end
$scope struct mem $end
$var string 1 {*||o \[0] $end
$var string 1 Bg,vB \[1] $end
$upscope $end
$upscope $end
$upscope $end
$scope struct r0 $end
$var wire 2 .0()- addr $end
$var wire 1 GEbRA en $end
$var wire 1 ;`9BK clk $end
$scope struct data $end
$var string 1 _Xe"P \[0] $end
$var string 1 jXrsx \[1] $end
$upscope $end
$upscope $end
$scope struct w1 $end
$var wire 2 '8u?z addr $end
$var wire 1 ~o=`& en $end
$var wire 1 *q>M1 clk $end
$scope struct data $end
$var string 1 N\zBe \[0] $end
$var string 1 c3h8{ \[1] $end
$upscope $end
$scope struct mask $end
$var wire 1 .SYGD \[0] $end
$var wire 1 />wYd \[1] $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
s sz>#|
s G._83
s 2r3#W
s AbGF%
s .^<$p
s ?s@Dc
s {*||o
s Bg,vB
0J(7*b
b0 @t0}\
078"T5
0G7v@m
s[,\x20] F&^FN
b0 "fUdW
0r1OK)
0,ADvU
s pD.mP
s !V!em
0l8dgD
01/sDs
b0 .0()-
0GEbRA
0;`9BK
s _Xe"P
s jXrsx
b0 '8u?z
0~o=`&
0*q>M1
s N\zBe
s c3h8{
0.SYGD
0/>wYd
$end
#500000
1J(7*b
1;`9BK
1*q>M1
#1000000
0J(7*b
1r1OK)
smem[0][0] pD.mP
smem[0][1] !V!em
1l8dgD
11/sDs
0;`9BK
1~o=`&
0*q>M1
smem[0][0] N\zBe
smem[0][1] c3h8{
1.SYGD
1/>wYd
#1500000
smem[0][0] sz>#|
smem[0][1] G._83
1J(7*b
1;`9BK
1*q>M1
#2000000
0J(7*b
b1 "fUdW
smem[1][0] pD.mP
smem[1][1] !V!em
0;`9BK
b1 '8u?z
0*q>M1
smem[1][0] N\zBe
smem[1][1] c3h8{
#2500000
smem[1][0] 2r3#W
smem[1][1] AbGF%
1J(7*b
1;`9BK
1*q>M1
#3000000
0J(7*b
b10 "fUdW
smem[2][0] pD.mP
smem[2][1] !V!em
0;`9BK
b10 '8u?z
0*q>M1
smem[2][0] N\zBe
smem[2][1] c3h8{
#3500000
smem[2][0] .^<$p
smem[2][1] ?s@Dc
1J(7*b
1;`9BK
1*q>M1
#4000000
0J(7*b
b11 "fUdW
smem[3][0] pD.mP
smem[3][1] !V!em
0;`9BK
b11 '8u?z
0*q>M1
smem[3][0] N\zBe
smem[3][1] c3h8{
#4500000
smem[3][0] {*||o
smem[3][1] Bg,vB
1J(7*b
1;`9BK
1*q>M1
#5000000
0J(7*b
b1 @t0}\
178"T5
s[mem[1][0],\x20mem[1][1]] F&^FN
b0 "fUdW
0r1OK)
s<!!!failed\x20to\x20format!!!> pD.mP
s<!!!failed\x20to\x20format!!!> !V!em
b1 .0()-
1GEbRA
0;`9BK
smem[1][0] _Xe"P
smem[1][1] jXrsx
b0 '8u?z
0~o=`&
0*q>M1
s<!!!failed\x20to\x20format!!!> N\zBe
s<!!!failed\x20to\x20format!!!> c3h8{
#5500000
1J(7*b
1;`9BK
1*q>M1
#6000000
0J(7*b
b1 "fUdW
1r1OK)
0;`9BK
b1 '8u?z
1~o=`&
0*q>M1
#6500000
s<!!!failed\x20to\x20format!!!> 2r3#W
s<!!!failed\x20to\x20format!!!> AbGF%
1J(7*b
s<!!!failed\x20to\x20format!!!> F&^FN
1;`9BK
s<!!!failed\x20to\x20format!!!> _Xe"P
s<!!!failed\x20to\x20format!!!> jXrsx
1*q>M1
#7000000

View file

@ -0,0 +1,855 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 5,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 26,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::enable_assert",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::any_seq_out",
ty: UInt<16>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk",
ty: Clock,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst",
ty: SyncReset,
},
SlotDebugData {
name: ".clk",
ty: Clock,
},
SlotDebugData {
name: ".rst",
ty: SyncReset,
},
SlotDebugData {
name: "<<Global>>::formal_global_clock",
ty: Clock,
},
SlotDebugData {
name: "<<Global>>::formal_reset",
ty: SyncReset,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<9>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "<<Global>>::any_seq",
ty: UInt<16>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
memories: StatePartLayout<Memories> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
insns: [
// at: module-XXXXXXXXXX.rs:15:1
0: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x4d2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::any_seq_out", ty: UInt<16> },
src: StatePartIndex<BigSlots>(25), // (0x4d2) SlotDebugData { name: "<<Global>>::any_seq", ty: UInt<16> },
},
// at: module-XXXXXXXXXX.rs:1:1
1: Copy {
dest: StatePartIndex<BigSlots>(19), // (0x0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "<<Global>>::formal_reset", ty: SyncReset },
},
2: NotU {
dest: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(19), // (0x0) SlotDebugData { name: "", ty: Bool },
width: 1,
},
3: Const {
dest: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
value: 0x1,
},
4: And {
dest: StatePartIndex<BigSlots>(21), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: Bool },
},
5: NotU {
dest: StatePartIndex<BigSlots>(22), // (0x0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(21), // (0x1) SlotDebugData { name: "", ty: Bool },
width: 1,
},
// at: module-XXXXXXXXXX.rs:12:1
6: Copy {
dest: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:9:1
7: Copy {
dest: StatePartIndex<BigSlots>(0), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count", ty: UInt<8> },
src: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
8: Const {
dest: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
value: 0xa,
},
9: CmpLe {
dest: StatePartIndex<BigSlots>(17), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
},
10: Or {
dest: StatePartIndex<BigSlots>(23), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(17), // (0x1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<BigSlots>(22), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:11:1
11: BranchIfZero {
target: 13,
value: StatePartIndex<BigSlots>(1), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::enable_assert", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:12:1
12: Copy {
dest: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(23), // (0x1) SlotDebugData { name: "", ty: Bool },
},
13: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(4), // (0x1 1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:1:1
14: Const {
dest: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
value: 0x1,
},
15: Add {
dest: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
lhs: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
},
16: CmpLt {
dest: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
rhs: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
},
17: CastToUInt {
dest: StatePartIndex<BigSlots>(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> },
src: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
dest_width: 8,
},
// at: module-XXXXXXXXXX.rs:4:1
18: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:5:1
19: BranchIfZero {
target: 21,
value: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:6:1
20: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
21: Const {
dest: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
value: 0x0,
},
// at: module-XXXXXXXXXX.rs:5:1
22: BranchIfNonZero {
target: 24,
value: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:7:1
23: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
24: Copy {
dest: StatePartIndex<BigSlots>(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock },
src: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "<<Global>>::formal_global_clock", ty: Clock },
},
25: Copy {
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset },
src: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "<<Global>>::formal_reset", ty: SyncReset },
},
// at: module-XXXXXXXXXX.rs:3:1
26: Copy {
dest: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock },
src: StatePartIndex<BigSlots>(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock },
},
27: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset },
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset },
},
// at: module-XXXXXXXXXX.rs:4:1
28: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock },
},
29: AndSmall {
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
30: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset },
},
31: BranchIfSmallZero {
target: 36,
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
32: BranchIfSmallNonZero {
target: 35,
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
33: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
src: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
},
34: Branch {
target: 36,
},
35: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:12:1
36: Assert {
clk_triggered: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
pred: StatePartIndex<SmallSlots>(4), // (0x1 1) SlotDebugData { name: "", ty: Bool },
assert_index: 0,
},
// at: module-XXXXXXXXXX.rs:4:1
37: XorSmallImmediate {
dest: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:1:1
38: Return,
],
..
},
pc: 38,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [
0,
0,
1,
0,
1,
],
},
big_slots: StatePart {
value: [
2,
1,
1234,
1,
0,
1,
0,
1,
0,
2,
3,
0,
1,
3,
10,
1,
3,
1,
1,
0,
1,
1,
0,
1,
1,
1234,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
},
global_io: {
SimIoForGlobal(
formal_global_clock,
): CompiledValue {
layout: CompiledTypeLayout {
ty: Clock,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::formal_global_clock",
ty: Clock,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 7, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
SimIoForGlobal(
formal_reset,
): CompiledValue {
layout: CompiledTypeLayout {
ty: SyncReset,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::formal_reset",
ty: SyncReset,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 8, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
SimIoForGlobal(
any_seq(
UInt<16>,
),
): CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<16>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::any_seq",
ty: UInt<16>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 5, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 25, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
},
main_module: SimulationModuleState {
base_targets: [
SimIoForGlobal(
formal_global_clock,
),
SimIoForGlobal(
formal_reset,
),
SimIoForGlobal(
any_seq(
UInt<16>,
),
),
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.count,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.enable_assert,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.any_seq_out,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.any_seq_out,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.count,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.enable_assert,
SimIoForGlobal(
any_seq(
UInt<16>,
),
),
SimIoForGlobal(
formal_global_clock,
),
SimIoForGlobal(
formal_reset,
),
},
did_initial_settle: true,
clocks_for_past: {},
},
extern_modules: [],
trace_decls: TraceModule {
name: "formal_counter",
children: [
TraceFormalInput {
name: "formal_global_clock",
child: TraceClock {
location: TraceScalarId(5),
name: "formal_global_clock",
flow: Source,
},
formal_input: formal_global_clock,
},
TraceFormalInput {
name: "formal_reset",
child: TraceSyncReset {
location: TraceScalarId(6),
name: "formal_reset",
flow: Source,
},
formal_input: formal_reset,
},
TraceFormalInput {
name: "any_seq",
child: TraceUInt {
location: TraceScalarId(8),
name: "any_seq",
ty: UInt<16>,
flow: Source,
},
formal_input: any_seq(
UInt<16>,
),
},
TraceModuleIO {
name: "count",
child: TraceUInt {
location: TraceScalarId(0),
name: "count",
ty: UInt<8>,
flow: Sink,
},
ty: UInt<8>,
flow: Sink,
},
TraceModuleIO {
name: "enable_assert",
child: TraceBool {
location: TraceScalarId(1),
name: "enable_assert",
flow: Source,
},
ty: Bool,
flow: Source,
},
TraceModuleIO {
name: "any_seq_out",
child: TraceUInt {
location: TraceScalarId(2),
name: "any_seq_out",
ty: UInt<16>,
flow: Sink,
},
ty: UInt<16>,
flow: Sink,
},
TraceWire {
name: "cd",
child: TraceBundle {
name: "cd",
fields: [
TraceClock {
location: TraceScalarId(3),
name: "clk",
flow: Duplex,
},
TraceSyncReset {
location: TraceScalarId(4),
name: "rst",
flow: Duplex,
},
],
ty: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
},
flow: Duplex,
},
ty: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
},
},
TraceReg {
name: "count_reg",
child: TraceUInt {
location: TraceScalarId(7),
name: "count_reg",
ty: UInt<8>,
flow: Duplex,
},
ty: UInt<8>,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: BigUInt {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x01,
},
SimTrace {
id: TraceScalarId(1),
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x1,
last_state: 0x1,
},
SimTrace {
id: TraceScalarId(2),
kind: BigUInt {
index: StatePartIndex<BigSlots>(2),
ty: UInt<16>,
},
maybe_changed: true,
state: 0x04d2,
last_state: 0x04d2,
},
SimTrace {
id: TraceScalarId(3),
kind: BigClock {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(4),
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(5),
kind: BigClock {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(6),
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(8),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(7),
kind: BigUInt {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x01,
},
SimTrace {
id: TraceScalarId(8),
kind: BigUInt {
index: StatePartIndex<BigSlots>(25),
ty: UInt<16>,
},
maybe_changed: true,
state: 0x04d2,
last_state: 0x04d2,
},
],
trace_memories: {},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
clocks_triggered: [
StatePartIndex<SmallSlots>(1),
],
event_queue: EventQueue(EventQueueData {
instant: 66 μs,
events: {},
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [
CompiledAssert {
instantiated_module: InstantiatedModule(formal_counter: formal_counter),
stmt_formal: assert {
clk: Wire(formal_counter::cd: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
}).clk,
pred: CmpLeU {
lhs: Reg {
name: formal_counter::count_reg,
ty: UInt<8>,
clock_domain: Wire(formal_counter::cd: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
}),
init: Some(
0x0_u8,
),
..
},
rhs: 0xA_u8,
literal_bits: Err(
NotALiteralExpr,
),
},
en: BitAndB {
lhs: true,
rhs: NotB {
arg: CastSyncResetToBool {
arg: formal_reset,
literal_bits: Err(
NotALiteralExpr,
),
},
literal_bits: Err(
NotALiteralExpr,
),
},
literal_bits: Err(
NotALiteralExpr,
),
},
text: "",
..
},
},
],
..
}

View file

@ -0,0 +1,290 @@
$timescale 1 ps $end
$scope module formal_counter $end
$var wire 1 ekAK2 formal_global_clock $end
$var wire 1 qTY9h formal_reset $end
$var wire 16 /roOY any_seq $end
$var wire 8 }eN0d count $end
$var wire 1 2f=;S enable_assert $end
$var wire 16 L-uG? any_seq_out $end
$scope struct cd $end
$var wire 1 -e"5` clk $end
$var wire 1 IC0;$ rst $end
$upscope $end
$var reg 8 ^:T_4 count_reg $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 }eN0d
12f=;S
b0 L-uG?
0-e"5`
1IC0;$
0ekAK2
1qTY9h
b0 ^:T_4
b0 /roOY
$end
#1000000
b10011010010 L-uG?
1-e"5`
1ekAK2
b10011010010 /roOY
0IC0;$
0qTY9h
#2000000
0-e"5`
0ekAK2
#3000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#4000000
0-e"5`
0ekAK2
#5000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#6000000
0-e"5`
0ekAK2
#7000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#8000000
0-e"5`
0ekAK2
#9000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#10000000
0-e"5`
0ekAK2
#11000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#12000000
0-e"5`
0ekAK2
#13000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#14000000
0-e"5`
0ekAK2
#15000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#16000000
0-e"5`
0ekAK2
#17000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#18000000
0-e"5`
0ekAK2
#19000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#20000000
0-e"5`
0ekAK2
#21000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#22000000
0-e"5`
0ekAK2
#23000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#24000000
0-e"5`
0ekAK2
#25000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#26000000
0-e"5`
0ekAK2
#27000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#28000000
0-e"5`
0ekAK2
#29000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#30000000
0-e"5`
0ekAK2
#31000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#32000000
0-e"5`
0ekAK2
#33000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#34000000
0-e"5`
0ekAK2
#35000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#36000000
0-e"5`
0ekAK2
#37000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#38000000
0-e"5`
0ekAK2
#39000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#40000000
0-e"5`
0ekAK2
#41000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#42000000
0-e"5`
0ekAK2
#43000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#44000000
0-e"5`
0ekAK2
#45000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#46000000
0-e"5`
0ekAK2
#47000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#48000000
0-e"5`
0ekAK2
#49000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#50000000
0-e"5`
0ekAK2
#51000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#52000000
0-e"5`
0ekAK2
#53000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#54000000
0-e"5`
0ekAK2
#55000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#56000000
0-e"5`
0ekAK2
#57000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#58000000
0-e"5`
0ekAK2
#59000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#60000000
0-e"5`
0ekAK2
#61000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#62000000
0-e"5`
0ekAK2
#63000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#64000000
0-e"5`
0ekAK2
#65000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#66000000

View file

@ -0,0 +1,194 @@
$timescale 1 ps $end
$scope module formal_counter $end
$var wire 1 ekAK2 formal_global_clock $end
$var wire 1 qTY9h formal_reset $end
$var wire 16 /roOY any_seq $end
$var wire 8 }eN0d count $end
$var wire 1 2f=;S enable_assert $end
$var wire 16 L-uG? any_seq_out $end
$scope struct cd $end
$var wire 1 -e"5` clk $end
$var wire 1 IC0;$ rst $end
$upscope $end
$var reg 8 ^:T_4 count_reg $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 }eN0d
02f=;S
b0 L-uG?
0-e"5`
1IC0;$
0ekAK2
1qTY9h
b0 ^:T_4
b0 /roOY
$end
#500000
b10011010010 L-uG?
1-e"5`
1ekAK2
b10011010010 /roOY
0IC0;$
0qTY9h
#1000000
0-e"5`
0ekAK2
#1500000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#2000000
0-e"5`
0ekAK2
#2500000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#3000000
0-e"5`
0ekAK2
#3500000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#4000000
0-e"5`
0ekAK2
#4500000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#5000000
0-e"5`
0ekAK2
#5500000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#6000000
0-e"5`
0ekAK2
#6500000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#7000000
0-e"5`
0ekAK2
#7500000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#8000000
0-e"5`
0ekAK2
#8500000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#9000000
0-e"5`
0ekAK2
#9500000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#10000000
0-e"5`
0ekAK2
#10500000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#11000000
0-e"5`
0ekAK2
#11500000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#12000000
0-e"5`
0ekAK2
#12500000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#13000000
0-e"5`
0ekAK2
#13500000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#14000000
0-e"5`
0ekAK2
#14500000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#15000000
0-e"5`
0ekAK2
#15500000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#16000000
0-e"5`
0ekAK2
#16500000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#17000000
12f=;S
0-e"5`
0ekAK2
#17500000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#18000000
0-e"5`
0ekAK2
#18500000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#19000000
0-e"5`
0ekAK2
#19500000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#20000000
0-e"5`
0ekAK2
#20500000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4

View file

@ -55,7 +55,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
271 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
281 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
@ -75,12 +75,12 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
761 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
52 | struct SimValueInner<T: Type> {
51 | struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
@ -95,7 +95,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
--> src/sim/value.rs
|
161 | pub struct SimValue<T: Type> {
160 | pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
@ -194,7 +194,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
271 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
281 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
@ -214,12 +214,12 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
761 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
52 | struct SimValueInner<T: Type> {
51 | struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
@ -234,7 +234,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
--> src/sim/value.rs
|
161 | pub struct SimValue<T: Type> {
160 | pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `intern_sized`
--> src/intern.rs
@ -306,7 +306,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
271 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
281 | pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
@ -326,12 +326,12 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
761 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
52 | struct SimValueInner<T: Type> {
51 | struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
@ -346,7 +346,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
--> src/sim/value.rs
|
161 | pub struct SimValue<T: Type> {
160 | pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs

View file

@ -51,7 +51,8 @@
"Reset": "Visible",
"Clock": "Visible",
"PhantomConst": "Visible",
"DynSimOnly": "Visible"
"DynSimOnly": "Visible",
"TraceAsString": "Visible"
}
},
"Bundle": {
@ -150,6 +151,11 @@
"$kind": "Opaque"
}
},
"NameIdOrGlobal": {
"data": {
"$kind": "ManualImpl"
}
},
"ScopedNameId": {
"data": {
"$kind": "Struct",
@ -1021,6 +1027,43 @@
"fold_where": "T: Fold<State>",
"visit_where": "T: Visit<State>"
},
"ops::ToTraceAsString": {
"data": {
"$kind": "Struct",
"$constructor": "ops::ToTraceAsString::new",
"inner()": "Visible",
"ty()": "Visible"
},
"generics": "<T: Type>",
"fold_where": "T: Fold<State>",
"visit_where": "T: Visit<State>"
},
"ops::TraceAsStringAsInner": {
"data": {
"$kind": "Struct",
"$constructor": "ops::TraceAsStringAsInner::new",
"arg_typed()": "Visible"
},
"generics": "<T: Type>",
"fold_where": "T: Fold<State>",
"visit_where": "T: Visit<State>"
},
"ops::SimIoForGlobal": {
"data": {
"$kind": "Struct",
"$constructor": "ops::SimIoForGlobal::new",
"global()": "Visible"
}
},
"ops::StructuralEq": {
"data": {
"$kind": "Struct",
"$constructor": "ops::StructuralEq::new_unchecked",
"lhs()": "Visible",
"rhs()": "Visible",
"assume_padding_is_zeroed()": "Visible"
}
},
"BlockId": {
"data": {
"$kind": "Opaque"
@ -1255,7 +1298,9 @@
"RegSync": "Visible",
"RegAsync": "Visible",
"Wire": "Visible",
"Instance": "Visible"
"Instance": "Visible",
"FormalInput": "Visible",
"SimIoForGlobal": "Visible"
}
},
"TargetChild": {
@ -1283,12 +1328,25 @@
"$kind": "Struct"
}
},
"TargetPathTraceAsStringInner": {
"data": {
"$kind": "Struct"
}
},
"TargetPathToTraceAsString": {
"data": {
"$kind": "Struct",
"ty": "Visible"
}
},
"TargetPathElement": {
"data": {
"$kind": "Enum",
"BundleField": "Visible",
"ArrayElement": "Visible",
"DynArrayElement": "Visible"
"DynArrayElement": "Visible",
"TraceAsStringInner": "Visible",
"ToTraceAsString": "Visible"
}
},
"PhantomConst": {
@ -1306,6 +1364,29 @@
"data": {
"$kind": "ManualImpl"
}
},
"TraceAsString": {
"data": {
"$kind": "ManualImpl"
},
"generics": "<T: Type>",
"fold_where": "T: Fold<State>",
"visit_where": "T: Visit<State>"
},
"FormalInput": {
"data": {
"$kind": "Struct",
"$constructor": "FormalInput::new",
"kind()": "Visible",
"name_id()": "Visible",
"ty()": "Visible",
"source_location()": "Visible"
}
},
"FormalInputKind": {
"data": {
"$kind": "Opaque"
}
}
}
}

View file

@ -47,7 +47,7 @@ function main()
*/LICENSE.md|*/Notices.txt)
# copyright file
;;
/crates/fayalite/tests/ui/*.stderr|/crates/fayalite/tests/sim/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.txt)
/crates/fayalite/tests/ui/*.stderr|/crates/fayalite/tests/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.txt)
# file that can't contain copyright header
;;
/.forgejo/workflows/*.yml|*/.gitignore|*.toml|*/Makefile|*/_CoqProject)