forked from libre-chip/fayalite
Compare commits
15 commits
orangecrab
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bb34aeb7f1 | |||
| 7ddb4780fa | |||
| b0e7873a17 | |||
| 1b16118ce5 | |||
| e2ca80af97 | |||
| 30ffd009f6 | |||
| 4bd6db3de8 | |||
| 98e7e91fc9 | |||
| ffca1a279d | |||
| d4d9706798 | |||
| 5d68885eaf | |||
| 31353862ce | |||
| b1116c4a1a | |||
| 6902aea3a6 | |||
| 1880ed682f |
96 changed files with 13927 additions and 1443 deletions
|
|
@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle {
|
||||||
let mut fields_expr_ne = vec![];
|
let mut fields_expr_ne = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
let mut fields_valueless_ne = vec![];
|
let mut fields_valueless_ne = vec![];
|
||||||
|
let mut fields_structural_eq = vec![];
|
||||||
for field in fields.named() {
|
for field in fields.named() {
|
||||||
let field_ident = field.ident();
|
let field_ident = field.ident();
|
||||||
let field_ty = field.ty();
|
let field_ty = field.ty();
|
||||||
|
|
@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||||
});
|
});
|
||||||
|
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
|
||||||
|
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||||
|
});
|
||||||
fields_value_eq.push(quote_spanned! {span=>
|
fields_value_eq.push(quote_spanned! {span=>
|
||||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#field_ident,
|
__lhs.#field_ident,
|
||||||
|
|
@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle {
|
||||||
let expr_ne_body;
|
let expr_ne_body;
|
||||||
let valueless_eq_body;
|
let valueless_eq_body;
|
||||||
let valueless_ne_body;
|
let valueless_ne_body;
|
||||||
|
let structural_eq;
|
||||||
if fields_len == 0 {
|
if fields_len == 0 {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
true
|
true
|
||||||
|
|
@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle {
|
||||||
valueless_ne_body = quote_spanned! {span=>
|
valueless_ne_body = quote_spanned! {span=>
|
||||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||||
};
|
};
|
||||||
|
structural_eq = quote_spanned! {span=>
|
||||||
|
true
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
#(#fields_value_eq)&*
|
#(#fields_value_eq)&*
|
||||||
|
|
@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle {
|
||||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||||
#(#fields_valueless_ne)|*
|
#(#fields_valueless_ne)|*
|
||||||
};
|
};
|
||||||
|
structural_eq = quote_spanned! {span=>
|
||||||
|
#(#fields_structural_eq)&&*
|
||||||
|
};
|
||||||
};
|
};
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__lhs: Self,
|
||||||
|
|
@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
|
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||||
|
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||||
|
::fayalite::expr::ops::StructuralEq::try_new(
|
||||||
|
::fayalite::expr::Expr::canonical(__lhs),
|
||||||
|
::fayalite::expr::Expr::canonical(__rhs),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||||
|
}
|
||||||
|
}
|
||||||
#expr_eq_body
|
#expr_eq_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
|
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_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
|
#expr_ne_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum {
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
#[allow(non_snake_case, dead_code)]
|
#[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(
|
::fayalite::sim::value::SimValue::from_value(
|
||||||
#self_token.#sim_builder_ty_field_ident,
|
#self_token.#sim_builder_ty_field_ident,
|
||||||
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
#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
|
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
fn fmt(
|
||||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
|
&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);
|
}.to_tokens(tokens);
|
||||||
|
|
@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum {
|
||||||
let mut variants_value_eq = vec![];
|
let mut variants_value_eq = vec![];
|
||||||
let mut variants_expr_eq = vec![];
|
let mut variants_expr_eq = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
|
let mut structural_eq: Option<TokenStream> = None;
|
||||||
for (
|
for (
|
||||||
variant_index,
|
variant_index,
|
||||||
ParsedVariant {
|
ParsedVariant {
|
||||||
|
|
@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#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>>::TRY_STRUCTURAL_EQ
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
structural_eq = Some(quote_spanned! {cmp_eq.span=>
|
||||||
|
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
variants_value_eq.push(quote_spanned! {span=>
|
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(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#variant_ident,
|
__lhs.#variant_ident,
|
||||||
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
||||||
|
|
@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum {
|
||||||
else {
|
else {
|
||||||
::fayalite::__std::unreachable!();
|
::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=>
|
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 {
|
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||||
variants_value_eq.push(quote_spanned! {span=>
|
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
|
__lhs_unknown == __rhs_unknown
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
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=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__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: 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 {
|
) -> ::fayalite::__std::primitive::bool {
|
||||||
match (&*__lhs_value, &*__rhs_value) {
|
match (&*__lhs_value, &*__rhs_value) {
|
||||||
#(#variants_value_eq)*
|
#(#variants_value_eq)*
|
||||||
|
|
@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::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>>::TRY_STRUCTURAL_EQ {
|
||||||
|
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||||
|
::fayalite::expr::ops::StructuralEq::try_new(
|
||||||
|
::fayalite::expr::Expr::canonical(__lhs),
|
||||||
|
::fayalite::expr::Expr::canonical(__rhs),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let __retval = ::fayalite::module::wire(
|
||||||
|
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
|
||||||
|
::fayalite::int::Bool,
|
||||||
|
);
|
||||||
::fayalite::module::connect(__retval, false);
|
::fayalite::module::connect(__retval, false);
|
||||||
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
||||||
#(#variants_expr_eq)*
|
#(#variants_expr_eq)*
|
||||||
|
|
@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimValue = #sim_value_ident #type_generics;
|
type SimValue = #sim_value_ident #type_generics;
|
||||||
type MatchVariant = #match_variant_ident #type_generics;
|
type MatchVariant = #match_variant_ident #type_generics;
|
||||||
type MatchActiveScope = ::fayalite::module::Scope;
|
type MatchActiveScope = ::fayalite::module::Scope;
|
||||||
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
type MatchVariantAndInactiveScope =
|
||||||
|
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||||
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
||||||
|
|
||||||
fn match_variants(
|
fn match_variants(
|
||||||
|
|
@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::int::Bool
|
::fayalite::int::Bool
|
||||||
}
|
}
|
||||||
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
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]
|
#[track_caller]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::__std::panic!("expected enum");
|
::fayalite::__std::panic!("expected enum");
|
||||||
};
|
};
|
||||||
let #variants_token = ::fayalite::enum_::EnumType::variants(&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 {
|
Self {
|
||||||
#(#from_canonical_body_fields)*
|
#(#from_canonical_body_fields)*
|
||||||
}
|
}
|
||||||
|
|
@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimBuilder = #sim_builder_ident #type_generics;
|
type SimBuilder = #sim_builder_ident #type_generics;
|
||||||
fn match_activate_scope(
|
fn match_activate_scope(
|
||||||
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
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();
|
let (#variant_access_token, scope) = v.activate();
|
||||||
(
|
(
|
||||||
match #variant_access_token.variant_index() {
|
match #variant_access_token.variant_index() {
|
||||||
|
|
@ -1200,7 +1262,10 @@ impl ToTokens for ParsedEnum {
|
||||||
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#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)
|
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum {
|
||||||
&self,
|
&self,
|
||||||
ty: #target #type_generics,
|
ty: #target #type_generics,
|
||||||
) -> ::fayalite::sim::value::SimValue<#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(
|
fn into_sim_value_with_type(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,10 @@ impl TargetedAnnotation {
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn assert_valid_target(target: Interned<Target>) {
|
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> {
|
pub fn target(&self) -> Interned<Target> {
|
||||||
self.target
|
self.target
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{
|
expr::{
|
||||||
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
|
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
|
||||||
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator},
|
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, StructuralEq},
|
||||||
},
|
},
|
||||||
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
|
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
|
||||||
intern::{Intern, Interned, LazyInterned},
|
intern::{Intern, Interned, LazyInterned},
|
||||||
|
|
@ -367,6 +367,8 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
|
||||||
where
|
where
|
||||||
Lhs: HdlPartialEqImpl<Rhs>,
|
Lhs: HdlPartialEqImpl<Rhs>,
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::TRY_STRUCTURAL_EQ;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
@ -387,6 +389,11 @@ where
|
||||||
}
|
}
|
||||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||||
|
if Self::TRY_STRUCTURAL_EQ {
|
||||||
|
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
|
||||||
|
return retval.to_expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
lhs.into_iter()
|
lhs.into_iter()
|
||||||
.zip(rhs)
|
.zip(rhs)
|
||||||
.map(|(l, r)| l.cmp_eq(r))
|
.map(|(l, r)| l.cmp_eq(r))
|
||||||
|
|
@ -396,6 +403,11 @@ where
|
||||||
}
|
}
|
||||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||||
|
if Self::TRY_STRUCTURAL_EQ {
|
||||||
|
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
|
||||||
|
return !retval.to_expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
lhs.into_iter()
|
lhs.into_iter()
|
||||||
.zip(rhs)
|
.zip(rhs)
|
||||||
.map(|(l, r)| l.cmp_ne(r))
|
.map(|(l, r)| l.cmp_ne(r))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
use eyre::{ContextCompat, eyre};
|
use eyre::{ContextCompat, eyre};
|
||||||
use petgraph::{
|
use petgraph::{
|
||||||
algo::{DfsSpace, kosaraju_scc, toposort},
|
algo::{DfsSpace, kosaraju_scc, toposort},
|
||||||
graph::DiGraph,
|
graph::{DiGraph, NodeIndex},
|
||||||
visit::{GraphBase, Visitable},
|
visit::{GraphBase, Visitable},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq};
|
||||||
|
|
@ -465,7 +465,7 @@ impl JobGraph {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("we know there's a cycle");
|
.expect("we know there's a cycle");
|
||||||
let cycle_set = HashSet::from_iter(cycle.iter().copied());
|
let cycle_set = HashSet::<NodeIndex>::from_iter(cycle.iter().copied());
|
||||||
let job = cycle
|
let job = cycle
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|node_id| {
|
.find_map(|node_id| {
|
||||||
|
|
@ -701,7 +701,7 @@ impl JobGraph {
|
||||||
job: DynJob,
|
job: DynJob,
|
||||||
thread: ScopedJoinHandle<'scope, eyre::Result<Vec<JobItem>>>,
|
thread: ScopedJoinHandle<'scope, eyre::Result<Vec<JobItem>>>,
|
||||||
}
|
}
|
||||||
let mut running_jobs = HashMap::default();
|
let mut running_jobs = HashMap::<NodeIndex, RunningJob>::default();
|
||||||
let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel();
|
let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel();
|
||||||
let mut next_finished_job = None;
|
let mut next_finished_job = None;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ impl ExternalCommand for UnadjustedVerilog {
|
||||||
args.write_arg("-o");
|
args.write_arg("-o");
|
||||||
args.write_interned_arg(unadjusted_verilog_file_name);
|
args.write_interned_arg(unadjusted_verilog_file_name);
|
||||||
if verilog_debug {
|
if verilog_debug {
|
||||||
args.write_args(["-g", "--preserve-values=all"]);
|
args.write_args(["-g", "--preserve-values=named"]);
|
||||||
}
|
}
|
||||||
if let Some(dialect) = verilog_dialect {
|
if let Some(dialect) = verilog_dialect {
|
||||||
args.write_args(dialect.firtool_extra_args().iter().copied());
|
args.write_args(dialect.firtool_extra_args().iter().copied());
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
expr::{
|
expr::{
|
||||||
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
|
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
|
||||||
Valueless,
|
Valueless,
|
||||||
ops::{ArrayLiteral, BundleLiteral},
|
ops::{ArrayLiteral, BundleLiteral, StructuralEq},
|
||||||
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
|
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
|
||||||
},
|
},
|
||||||
int::{Bool, DynSize},
|
int::{Bool, DynSize},
|
||||||
|
|
@ -708,6 +708,8 @@ macro_rules! impl_tuples {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::TRY_STRUCTURAL_EQ)*;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
@ -725,6 +727,11 @@ macro_rules! impl_tuples {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
|
if Self::TRY_STRUCTURAL_EQ {
|
||||||
|
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
|
||||||
|
return retval.to_expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
let ($($lhs_var,)*) = *lhs;
|
let ($($lhs_var,)*) = *lhs;
|
||||||
let ($($rhs_var,)*) = *rhs;
|
let ($($rhs_var,)*) = *rhs;
|
||||||
ArrayLiteral::<Bool, DynSize>::new(
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
|
@ -737,6 +744,11 @@ macro_rules! impl_tuples {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
|
if Self::TRY_STRUCTURAL_EQ {
|
||||||
|
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
|
||||||
|
return !retval.to_expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
let ($($lhs_var,)*) = *lhs;
|
let ($($lhs_var,)*) = *lhs;
|
||||||
let ($($rhs_var,)*) = *rhs;
|
let ($($rhs_var,)*) = *rhs;
|
||||||
ArrayLiteral::<Bool, DynSize>::new(
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
bundle::{Bundle, BundleType},
|
bundle::{Bundle, BundleType},
|
||||||
enum_::{Enum, EnumType},
|
enum_::{Enum, EnumType},
|
||||||
expr::target::{GetTarget, Target},
|
expr::target::{GetTarget, Target},
|
||||||
|
formal::FormalInput,
|
||||||
int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
|
int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{DynPortType, MemPort, PortType},
|
memory::{DynPortType, MemPort, PortType},
|
||||||
|
|
@ -220,6 +221,7 @@ expr_enum! {
|
||||||
CastBitsTo(ops::CastBitsTo),
|
CastBitsTo(ops::CastBitsTo),
|
||||||
ToTraceAsString(ops::ToTraceAsString),
|
ToTraceAsString(ops::ToTraceAsString),
|
||||||
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
||||||
|
StructuralEq(ops::StructuralEq),
|
||||||
ModuleIO(ModuleIO<CanonicalType>),
|
ModuleIO(ModuleIO<CanonicalType>),
|
||||||
Instance(Instance<Bundle>),
|
Instance(Instance<Bundle>),
|
||||||
Wire(Wire<CanonicalType>),
|
Wire(Wire<CanonicalType>),
|
||||||
|
|
@ -227,6 +229,8 @@ expr_enum! {
|
||||||
RegSync(Reg<CanonicalType, SyncReset>),
|
RegSync(Reg<CanonicalType, SyncReset>),
|
||||||
RegAsync(Reg<CanonicalType, AsyncReset>),
|
RegAsync(Reg<CanonicalType, AsyncReset>),
|
||||||
MemPort(MemPort<DynPortType>),
|
MemPort(MemPort<DynPortType>),
|
||||||
|
FormalInput(FormalInput),
|
||||||
|
SimIoForGlobal(ops::SimIoForGlobal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,6 +702,7 @@ macro_rules! impl_hdl_cmp {
|
||||||
impl_helper = $HdlCmpImplHelper:ident,
|
impl_helper = $HdlCmpImplHelper:ident,
|
||||||
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
||||||
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
||||||
|
$(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)?
|
||||||
]
|
]
|
||||||
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
||||||
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
||||||
|
|
@ -726,6 +731,8 @@ macro_rules! impl_hdl_cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
||||||
|
$(const $TRY_STRUCTURAL_EQ: bool;)?
|
||||||
|
|
||||||
$(#[track_caller]
|
$(#[track_caller]
|
||||||
fn $cmp_value_fn(
|
fn $cmp_value_fn(
|
||||||
$cmp_value_lhs: Self,
|
$cmp_value_lhs: Self,
|
||||||
|
|
@ -909,6 +916,7 @@ impl_hdl_cmp! {
|
||||||
#[
|
#[
|
||||||
impl_helper = HdlPartialEqImplHelper,
|
impl_helper = HdlPartialEqImplHelper,
|
||||||
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
||||||
|
try_structural_eq = TRY_STRUCTURAL_EQ,
|
||||||
]
|
]
|
||||||
pub trait HdlPartialEq<Rhs: ValueType>:
|
pub trait HdlPartialEq<Rhs: ValueType>:
|
||||||
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
||||||
|
|
@ -1908,3 +1916,19 @@ impl<T: ?Sized + ValueType> ToTraceAsStringImpl<T::Type, value_category::ValueCa
|
||||||
Valueless::new(ty.with_new_inner_ty(this.ty().intern_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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ use crate::{
|
||||||
},
|
},
|
||||||
value_category::ValueCategoryExpr,
|
value_category::ValueCategoryExpr,
|
||||||
},
|
},
|
||||||
|
formal::FormalInput,
|
||||||
int::{
|
int::{
|
||||||
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
||||||
UIntType, UIntValue,
|
UIntType, UIntValue,
|
||||||
},
|
},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned, MemoizeGeneric},
|
||||||
phantom_const::{PhantomConst, PhantomConstValue},
|
phantom_const::{PhantomConst, PhantomConstValue},
|
||||||
reset::{
|
reset::{
|
||||||
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
||||||
|
|
@ -2983,6 +2984,7 @@ macro_rules! impl_compare_op {
|
||||||
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
|
#[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)]
|
#[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)]
|
#[type($Lhs:ty, $Rhs:ty)]
|
||||||
|
$(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])?
|
||||||
#[trait($Trait:ident)]
|
#[trait($Trait:ident)]
|
||||||
$(
|
$(
|
||||||
struct $name:ident;
|
struct $name:ident;
|
||||||
|
|
@ -3044,6 +3046,7 @@ macro_rules! impl_compare_op {
|
||||||
})*
|
})*
|
||||||
|
|
||||||
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
||||||
|
$(const $TRY_STRUCTURAL_EQ: bool = true;)?
|
||||||
$(fn $value_method(
|
$(fn $value_method(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
||||||
|
|
@ -3064,6 +3067,7 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
||||||
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
||||||
#[type(Bool, Bool)]
|
#[type(Bool, Bool)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3087,6 +3091,7 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
#[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())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3111,6 +3116,7 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
#[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())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3132,6 +3138,8 @@ impl_compare_op! {
|
||||||
macro_rules! impl_compare_forwards_to_bool {
|
macro_rules! impl_compare_forwards_to_bool {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl HdlPartialEqImpl<Self> for $ty {
|
impl HdlPartialEqImpl<Self> for $ty {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -4881,3 +4889,336 @@ impl<T: Type> ToExpr for TraceAsStringAsInner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct StructuralEqFlags {
|
||||||
|
pub assume_padding_is_zeroed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructuralEqFlags {
|
||||||
|
pub const DEFAULT: Self = Self {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StructuralEqFlags {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum StructuralEqError {
|
||||||
|
TypesAreNotEqual {
|
||||||
|
lhs: CanonicalType,
|
||||||
|
rhs: CanonicalType,
|
||||||
|
},
|
||||||
|
TypeContainsSimOnly {
|
||||||
|
ty: CanonicalType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StructuralEqError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::TypesAreNotEqual { lhs, rhs } => write!(
|
||||||
|
f,
|
||||||
|
"StructuralEq lhs type must be the same as rhs type:\nlhs: {lhs:#?}\nrhs: {rhs:#?}\n",
|
||||||
|
),
|
||||||
|
Self::TypeContainsSimOnly { ty } => write!(
|
||||||
|
f,
|
||||||
|
"StructuralEq input type must not contain SimOnly type: {ty:#?}",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct StructuralEq {
|
||||||
|
lhs: Expr<CanonicalType>,
|
||||||
|
rhs: Expr<CanonicalType>,
|
||||||
|
flags: StructuralEqFlags,
|
||||||
|
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::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn with_flags(
|
||||||
|
lhs: Expr<CanonicalType>,
|
||||||
|
rhs: Expr<CanonicalType>,
|
||||||
|
flags: StructuralEqFlags,
|
||||||
|
) -> Self {
|
||||||
|
match Self::try_with_flags(lhs, rhs, flags) {
|
||||||
|
Ok(retval) => retval,
|
||||||
|
Err(e) => panic!("{e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_new(
|
||||||
|
lhs: Expr<CanonicalType>,
|
||||||
|
rhs: Expr<CanonicalType>,
|
||||||
|
) -> Result<Self, StructuralEqError> {
|
||||||
|
Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
||||||
|
}
|
||||||
|
pub fn try_with_flags(
|
||||||
|
lhs: Expr<CanonicalType>,
|
||||||
|
rhs: Expr<CanonicalType>,
|
||||||
|
flags: StructuralEqFlags,
|
||||||
|
) -> Result<Self, StructuralEqError> {
|
||||||
|
let ty = lhs.ty();
|
||||||
|
let rhs_ty = rhs.ty();
|
||||||
|
if ty != rhs_ty {
|
||||||
|
return Err(StructuralEqError::TypesAreNotEqual {
|
||||||
|
lhs: ty,
|
||||||
|
rhs: rhs_ty,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ty.contains_sim_only() {
|
||||||
|
return Err(StructuralEqError::TypeContainsSimOnly { ty });
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
flags,
|
||||||
|
literal_bits: lhs.to_literal_bits().and_then(|lhs| {
|
||||||
|
let rhs = rhs.to_literal_bits()?;
|
||||||
|
if flags.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 flags(self) -> StructuralEqFlags {
|
||||||
|
self.flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
array::Array,
|
array::Array,
|
||||||
bundle::{Bundle, BundleField},
|
bundle::{Bundle, BundleField},
|
||||||
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
|
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
|
||||||
|
formal::FormalInput,
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{DynPortType, MemPort},
|
memory::{DynPortType, MemPort},
|
||||||
module::{Instance, ModuleIO, TargetName},
|
module::{Instance, ModuleIO, TargetName},
|
||||||
|
|
@ -62,7 +63,7 @@ pub struct TargetPathToTraceAsString {
|
||||||
|
|
||||||
impl fmt::Display for TargetPathToTraceAsString {
|
impl fmt::Display for TargetPathToTraceAsString {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, ".to_trace_as_string(...)")
|
write!(f, ".to_trace_as_string()")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,6 +296,14 @@ impl_target_base! {
|
||||||
#[is = is_instance]
|
#[is = is_instance]
|
||||||
#[to = instance]
|
#[to = instance]
|
||||||
Instance(Instance<Bundle>),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,6 +352,8 @@ impl TargetBase {
|
||||||
TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None),
|
TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None),
|
||||||
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
|
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
|
||||||
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
|
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
|
||||||
|
TargetBase::FormalInput(v) => TargetName(v.scoped_name(), None),
|
||||||
|
TargetBase::SimIoForGlobal(v) => TargetName(v.global().scoped_name(), None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn canonical_ty(&self) -> CanonicalType {
|
pub fn canonical_ty(&self) -> CanonicalType {
|
||||||
|
|
@ -354,6 +365,21 @@ impl TargetBase {
|
||||||
TargetBase::RegAsync(v) => v.ty(),
|
TargetBase::RegAsync(v) => v.ty(),
|
||||||
TargetBase::Wire(v) => v.ty(),
|
TargetBase::Wire(v) => v.ty(),
|
||||||
TargetBase::Instance(v) => v.ty().canonical(),
|
TargetBase::Instance(v) => v.ty().canonical(),
|
||||||
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -548,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]
|
#[must_use]
|
||||||
pub fn join(&self, path_element: Interned<TargetPathElement>) -> Self {
|
pub fn join(&self, path_element: Interned<TargetPathElement>) -> Self {
|
||||||
TargetChild::new(self.intern(), path_element).into()
|
TargetChild::new(self.intern(), path_element).into()
|
||||||
|
|
@ -664,6 +700,18 @@ pub trait GetTarget {
|
||||||
fn target(&self) -> Option<Interned<Target>>;
|
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 {
|
impl GetTarget for bool {
|
||||||
fn target(&self) -> Option<Interned<Target>> {
|
fn target(&self) -> Option<Interned<Target>> {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,189 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{
|
use crate::{
|
||||||
|
expr::target::{GetTarget, Target},
|
||||||
int::BoolOrIntType,
|
int::BoolOrIntType,
|
||||||
intern::{Intern, Interned, Memoize},
|
intern::{Intern, Interned},
|
||||||
|
module::{NameId, NameIdOrGlobal, ScopedNameId},
|
||||||
prelude::*,
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub enum FormalKind {
|
pub enum FormalKind {
|
||||||
|
|
@ -138,110 +316,76 @@ make_formal!(
|
||||||
hdl_cover
|
hdl_cover
|
||||||
);
|
);
|
||||||
|
|
||||||
pub trait MakeFormalExpr: Type {}
|
|
||||||
|
|
||||||
impl<T: Type> MakeFormalExpr for T {}
|
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn formal_global_clock() -> Expr<Clock> {
|
pub fn formal_global_clock() -> Expr<Clock> {
|
||||||
#[hdl_module(extern)]
|
static CACHE: OnceLock<Expr<Clock>> = OnceLock::new();
|
||||||
fn formal_global_clock() {
|
*CACHE.get_or_init(|| {
|
||||||
#[hdl]
|
let kind = FormalInputKind::FormalGlobalClock;
|
||||||
let clk: Clock = m.output();
|
Expr::from_canonical(
|
||||||
m.annotate_module(BlackBoxInlineAnnotation {
|
FormalInput::new(
|
||||||
path: "fayalite_formal_global_clock.v".intern(),
|
kind,
|
||||||
text: r"module __fayalite_formal_global_clock(output clk);
|
NameId(
|
||||||
(* gclk *)
|
kind.interned_name(),
|
||||||
reg clk;
|
kind.fixed_id().expect("known to have a fixed Id"),
|
||||||
endmodule
|
),
|
||||||
"
|
Clock.into(),
|
||||||
.intern(),
|
kind.fixed_source_location()
|
||||||
});
|
.expect("known to have a fixed SourceLocation"),
|
||||||
m.verilog_name("__fayalite_formal_global_clock");
|
)
|
||||||
}
|
.to_expr(),
|
||||||
#[hdl]
|
)
|
||||||
let formal_global_clock = instance(formal_global_clock());
|
})
|
||||||
formal_global_clock.clk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn formal_reset() -> Expr<SyncReset> {
|
pub fn formal_reset() -> Expr<SyncReset> {
|
||||||
#[hdl_module(extern)]
|
static CACHE: OnceLock<Expr<SyncReset>> = OnceLock::new();
|
||||||
fn formal_reset() {
|
*CACHE.get_or_init(|| {
|
||||||
#[hdl]
|
let kind = FormalInputKind::FormalReset;
|
||||||
let rst: SyncReset = m.output();
|
Expr::from_canonical(
|
||||||
m.annotate_module(BlackBoxInlineAnnotation {
|
FormalInput::new(
|
||||||
path: "fayalite_formal_reset.v".intern(),
|
kind,
|
||||||
text: r"module __fayalite_formal_reset(output rst);
|
NameId(
|
||||||
assign rst = $initstate;
|
kind.interned_name(),
|
||||||
endmodule
|
kind.fixed_id().expect("known to have a fixed Id"),
|
||||||
"
|
),
|
||||||
.intern(),
|
SyncReset.into(),
|
||||||
});
|
kind.fixed_source_location()
|
||||||
m.verilog_name("__fayalite_formal_reset");
|
.expect("known to have a fixed SourceLocation"),
|
||||||
}
|
)
|
||||||
static MOD: OnceLock<Interned<Module<formal_reset>>> = OnceLock::new();
|
.to_expr(),
|
||||||
#[hdl]
|
)
|
||||||
let formal_reset = instance(*MOD.get_or_init(formal_reset));
|
})
|
||||||
formal_reset.rst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! make_any_const_fn {
|
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]
|
#[hdl]
|
||||||
pub fn $ident<T: BoolOrIntType>(ty: T) -> Expr<T> {
|
pub fn $ident<T: BoolOrIntType>(ty: T) -> Expr<T> {
|
||||||
#[hdl_module(extern)]
|
$ident_with_loc(ty, SourceLocation::caller())
|
||||||
pub(super) fn $ident<T: BoolOrIntType>(ty: T) {
|
}
|
||||||
#[hdl]
|
#[track_caller]
|
||||||
let out: T = m.output(ty);
|
#[hdl]
|
||||||
let width = ty.width();
|
pub fn $ident_with_loc<T: BoolOrIntType>(
|
||||||
let verilog_bitslice = if width == 1 {
|
ty: T,
|
||||||
String::new()
|
source_location: SourceLocation,
|
||||||
} else {
|
) -> Expr<T> {
|
||||||
format!(" [{}:0]", width - 1)
|
let kind = FormalInputKind::$kind;
|
||||||
};
|
Expr::from_canonical(
|
||||||
m.annotate_module(BlackBoxInlineAnnotation {
|
FormalInput::new(
|
||||||
path: Intern::intern_owned(format!(
|
kind,
|
||||||
"fayalite_{}_{width}.v",
|
NameId(kind.interned_name(), crate::module::Id::new()),
|
||||||
stringify!($ident),
|
ty.canonical(),
|
||||||
)),
|
source_location,
|
||||||
text: Intern::intern_owned(format!(
|
)
|
||||||
r"module __fayalite_{}_{width}(output{verilog_bitslice} out);
|
.to_expr(),
|
||||||
(* {} *)
|
)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
make_any_const_fn!(any_const, "anyconst");
|
make_any_const_fn!(any_const, any_const_with_loc, "anyconst", AnyConst);
|
||||||
make_any_const_fn!(any_seq, "anyseq");
|
make_any_const_fn!(any_seq, any_seq_with_loc, "anyseq", AnySeq);
|
||||||
make_any_const_fn!(all_const, "allconst");
|
make_any_const_fn!(all_const, all_const_with_loc, "allconst", AllConst);
|
||||||
make_any_const_fn!(all_seq, "allseq");
|
make_any_const_fn!(all_seq, all_seq_with_loc, "allseq", AllSeq);
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,8 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type {
|
||||||
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
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>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
||||||
for $UIntInRangeType<Start, End>
|
for $UIntInRangeType<Start, End>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
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>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
||||||
for UIntType<Width>
|
for UIntType<Width>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
|
||||||
|
|
@ -682,27 +682,62 @@ impl<T: ?Sized + 'static + Send + Sync + AsRef<U>, U: ?Sized> AsRef<U> for Inter
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InternedSliceIter<T: Clone + 'static + Send + Sync> {
|
pub struct InternedSliceIter<T: Clone + 'static + Send + Sync> {
|
||||||
slice: Interned<[T]>,
|
iter: std::iter::Cloned<std::slice::Iter<'static, T>>,
|
||||||
index: std::ops::Range<usize>,
|
}
|
||||||
|
|
||||||
|
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> {
|
impl<T: Clone + 'static + Send + Sync> Iterator for InternedSliceIter<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
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>) {
|
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> {
|
impl<T: Clone + 'static + Send + Sync> DoubleEndedIterator for InternedSliceIter<T> {
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
self.index
|
self.iter.next_back()
|
||||||
.next_back()
|
}
|
||||||
.map(|index| self.slice[index].clone())
|
|
||||||
|
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 {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
InternedSliceIter {
|
InternedSliceIter {
|
||||||
index: 0..self.len(),
|
iter: Interned::into_inner(self).iter().cloned(),
|
||||||
slice: self,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
clock::{Clock, ClockDomain},
|
clock::{Clock, ClockDomain},
|
||||||
enum_::{Enum, EnumMatchVariantsIter, EnumType},
|
enum_::{Enum, EnumMatchVariantsIter, EnumType},
|
||||||
expr::{
|
expr::{
|
||||||
Expr, Flow, ToExpr, ValueType,
|
Expr, ExprEnum, Flow, ToExpr, ValueType,
|
||||||
ops::VariantAccess,
|
ops::VariantAccess,
|
||||||
target::{
|
target::{
|
||||||
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
|
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
|
||||||
|
|
@ -20,6 +20,7 @@ use crate::{
|
||||||
int::{Bool, DynSize, Size},
|
int::{Bool, DynSize, Size},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
|
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
|
||||||
|
module::transform::visit::{Visit, Visitor},
|
||||||
platform::PlatformIOBuilder,
|
platform::PlatformIOBuilder,
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
||||||
|
|
@ -726,7 +727,57 @@ impl fmt::Display for NameId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[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 {
|
impl fmt::Debug for ScopedNameId {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|
@ -804,7 +855,7 @@ impl<T: BundleType> Instance<T> {
|
||||||
self.containing_module_name_id().0
|
self.containing_module_name_id().0
|
||||||
}
|
}
|
||||||
pub fn containing_module_name_id(self) -> NameId {
|
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> {
|
pub fn name(self) -> Interned<str> {
|
||||||
self.name_id().0
|
self.name_id().0
|
||||||
|
|
@ -821,11 +872,13 @@ impl<T: BundleType> Instance<T> {
|
||||||
pub fn source_location(self) -> SourceLocation {
|
pub fn source_location(self) -> SourceLocation {
|
||||||
self.source_location
|
self.source_location
|
||||||
}
|
}
|
||||||
|
#[track_caller]
|
||||||
pub fn new_unchecked(
|
pub fn new_unchecked(
|
||||||
scoped_name: ScopedNameId,
|
scoped_name: ScopedNameId,
|
||||||
instantiated: Interned<Module<T>>,
|
instantiated: Interned<Module<T>>,
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
scoped_name.0.assert_is_name_id();
|
||||||
Self {
|
Self {
|
||||||
scoped_name,
|
scoped_name,
|
||||||
instantiated,
|
instantiated,
|
||||||
|
|
@ -1598,12 +1651,63 @@ impl TargetState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
struct AssertValidityState {
|
||||||
module: Module<Bundle>,
|
module: Module<Bundle>,
|
||||||
blocks: Vec<Block>,
|
blocks: Vec<Block>,
|
||||||
|
visible_exprs: VisibleExprsStack,
|
||||||
target_states: HashMap<Interned<TargetBase>, TargetState>,
|
target_states: HashMap<Interned<TargetBase>, TargetState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GetTargetStatesError {
|
||||||
|
NotFound,
|
||||||
|
IsGlobal,
|
||||||
|
FoundSimIoForGlobal(crate::expr::ops::SimIoForGlobal),
|
||||||
|
}
|
||||||
|
|
||||||
impl AssertValidityState {
|
impl AssertValidityState {
|
||||||
fn make_block_index(&mut self, block: Block) -> usize {
|
fn make_block_index(&mut self, block: Block) -> usize {
|
||||||
let retval = self.blocks.len();
|
let retval = self.blocks.len();
|
||||||
|
|
@ -1614,7 +1718,7 @@ impl AssertValidityState {
|
||||||
&'a self,
|
&'a self,
|
||||||
target: Target,
|
target: Target,
|
||||||
process_target_state: &dyn Fn(&'a TargetState, bool),
|
process_target_state: &dyn Fn(&'a TargetState, bool),
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), GetTargetStatesError> {
|
||||||
let mut target = target.unwrap_transparent_types();
|
let mut target = target.unwrap_transparent_types();
|
||||||
loop {
|
loop {
|
||||||
break match target {
|
break match target {
|
||||||
|
|
@ -1667,8 +1771,24 @@ impl AssertValidityState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_base_state(&self, target_base: Interned<TargetBase>) -> Result<&TargetState, ()> {
|
fn get_base_state(
|
||||||
self.target_states.get(&target_base).ok_or(())
|
&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]
|
#[track_caller]
|
||||||
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
|
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
|
||||||
|
|
@ -1761,16 +1881,30 @@ impl AssertValidityState {
|
||||||
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);
|
Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown);
|
||||||
});
|
});
|
||||||
if result.is_err() {
|
match result {
|
||||||
if is_lhs {
|
Ok(()) => {}
|
||||||
panic!("at {source_location}: tried to connect to not-yet-defined item: {target}");
|
Err(GetTargetStatesError::NotFound) => {
|
||||||
} else {
|
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!(
|
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(
|
fn process_conditional_sub_blocks(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_block: usize,
|
parent_block: usize,
|
||||||
|
|
@ -1784,17 +1918,40 @@ impl AssertValidityState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[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) {
|
fn assert_subtree_validity(&mut self, block: usize) {
|
||||||
|
self.visible_exprs.push_empty();
|
||||||
let module = self.module;
|
let module = self.module;
|
||||||
if block == 0 {
|
if block == 0 {
|
||||||
for module_io in &*module.module_io {
|
for module_io in &*module.module_io {
|
||||||
self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block);
|
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];
|
let Block { memories, stmts } = self.blocks[block];
|
||||||
for m in memories {
|
for m in memories {
|
||||||
for port in m.ports() {
|
for port in m.ports() {
|
||||||
self.insert_new_base(TargetBase::intern_sized(port.into()), block);
|
self.insert_new_base(TargetBase::intern_sized(port.into()), block);
|
||||||
|
self.visible_exprs.top().insert(port.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
|
|
@ -1808,44 +1965,104 @@ impl AssertValidityState {
|
||||||
} = connect;
|
} = connect;
|
||||||
self.set_connect_side_written(lhs, source_location, true, block);
|
self.set_connect_side_written(lhs, source_location, true, block);
|
||||||
self.set_connect_side_written(rhs, source_location, false, 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) => {
|
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)
|
self.process_conditional_sub_blocks(block, sub_blocks)
|
||||||
}
|
}
|
||||||
Stmt::Match(match_stmt) => {
|
Stmt::Match(match_stmt) => {
|
||||||
match_stmt.assert_validity();
|
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(
|
let sub_blocks = Vec::from_iter(
|
||||||
match_stmt
|
sub_blocks
|
||||||
.blocks
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|block| self.make_block_index(block)),
|
.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 {
|
Stmt::Declaration(StmtDeclaration::Wire(StmtWire {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
wire,
|
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 {
|
Stmt::Declaration(StmtDeclaration::Reg(StmtReg {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
reg,
|
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 {
|
Stmt::Declaration(StmtDeclaration::RegSync(StmtReg {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
reg,
|
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 {
|
Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
reg,
|
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 {
|
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
instance,
|
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]
|
#[track_caller]
|
||||||
fn assert_validity(&mut self) {
|
fn assert_validity(&mut self) {
|
||||||
|
|
@ -1874,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> {
|
impl<T: BundleType> Module<T> {
|
||||||
/// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead
|
/// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|
@ -1894,7 +2248,7 @@ impl<T: BundleType> Module<T> {
|
||||||
clocks_for_past,
|
clocks_for_past,
|
||||||
simulation: Some(simulation),
|
simulation: Some(simulation),
|
||||||
}) => {
|
}) => {
|
||||||
let mut clocks_for_past_set = HashSet::default();
|
let mut clocks_for_past_set = HashSet::<Target>::default();
|
||||||
*clocks_for_past = clocks_for_past
|
*clocks_for_past = clocks_for_past
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
|
@ -1915,7 +2269,9 @@ impl<T: BundleType> Module<T> {
|
||||||
}
|
}
|
||||||
if simulation.sim_io_to_generator_map.len() > module_io.len() {
|
if simulation.sim_io_to_generator_map.len() > module_io.len() {
|
||||||
// if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io
|
// if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io
|
||||||
let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io));
|
let module_io_set = HashSet::<ModuleIO<CanonicalType>>::from_iter(
|
||||||
|
module_io.iter().map(|v| v.module_io),
|
||||||
|
);
|
||||||
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
|
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
|
||||||
if !module_io_set.contains(&**sim_io) {
|
if !module_io_set.contains(&**sim_io) {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
@ -1999,6 +2355,7 @@ impl<T: BundleType> Module<T> {
|
||||||
AssertValidityState {
|
AssertValidityState {
|
||||||
module: self.canonical(),
|
module: self.canonical(),
|
||||||
blocks: vec![],
|
blocks: vec![],
|
||||||
|
visible_exprs: VisibleExprsStack::default(),
|
||||||
target_states: HashMap::with_capacity_and_hasher(64, Default::default()),
|
target_states: HashMap::with_capacity_and_hasher(64, Default::default()),
|
||||||
}
|
}
|
||||||
.assert_validity();
|
.assert_validity();
|
||||||
|
|
@ -2104,7 +2461,7 @@ impl<T: Type, R: ResetType> RegBuilder<Expr<ClockDomain<R>>, Option<Expr<T>>, T>
|
||||||
ty,
|
ty,
|
||||||
} = self;
|
} = self;
|
||||||
ModuleBuilder::with(|module_builder| {
|
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 reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init);
|
||||||
let retval = reg.to_expr();
|
let retval = reg.to_expr();
|
||||||
// convert before borrow_mut since ModuleBuilder could be reentered by T::canonical()
|
// convert before borrow_mut since ModuleBuilder could be reentered by T::canonical()
|
||||||
|
|
@ -2500,6 +2857,9 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
|
||||||
instance,
|
instance,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
|
||||||
|
unreachable!("not a valid annotation target")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ModuleBuilder::with(|m| {
|
ModuleBuilder::with(|m| {
|
||||||
unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt())
|
unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt())
|
||||||
|
|
@ -2514,7 +2874,7 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn wire_with_loc<T: Type>(name: &str, source_location: SourceLocation, ty: T) -> Expr<T> {
|
pub fn wire_with_loc<T: Type>(name: &str, source_location: SourceLocation, ty: T) -> Expr<T> {
|
||||||
ModuleBuilder::with(|m| {
|
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 wire = Wire::<T>::new_unchecked(scoped_name, source_location, ty);
|
||||||
let retval = wire.to_expr();
|
let retval = wire.to_expr();
|
||||||
let canonical_wire = wire.canonical();
|
let canonical_wire = wire.canonical();
|
||||||
|
|
@ -2546,7 +2906,7 @@ fn incomplete_declaration(
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
) -> Rc<RefCell<IncompleteDeclaration>> {
|
) -> Rc<RefCell<IncompleteDeclaration>> {
|
||||||
ModuleBuilder::with(|m| {
|
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 {
|
let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete {
|
||||||
name: scoped_name,
|
name: scoped_name,
|
||||||
source_location,
|
source_location,
|
||||||
|
|
@ -2722,7 +3082,7 @@ pub fn instance_with_loc<T: BundleType>(
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
) -> Expr<T> {
|
) -> Expr<T> {
|
||||||
ModuleBuilder::with(|m| {
|
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> {
|
let instance = Instance::<T> {
|
||||||
scoped_name,
|
scoped_name,
|
||||||
instantiated,
|
instantiated,
|
||||||
|
|
@ -2761,7 +3121,7 @@ fn memory_impl<Element: Type, Len: Size>(
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
) -> MemBuilder<Element, Len> {
|
) -> MemBuilder<Element, Len> {
|
||||||
ModuleBuilder::with(|m| {
|
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 (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type);
|
||||||
let mut impl_ = m.impl_.borrow_mut();
|
let mut impl_ = m.impl_.borrow_mut();
|
||||||
let body = impl_.body.builder_normal_body();
|
let body = impl_.body.builder_normal_body();
|
||||||
|
|
@ -2916,7 +3276,7 @@ impl<T: Type> ModuleIO<T> {
|
||||||
NameId(self.bundle_field.name, self.id)
|
NameId(self.bundle_field.name, self.id)
|
||||||
}
|
}
|
||||||
pub fn scoped_name(&self) -> ScopedNameId {
|
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 {
|
pub fn source_location(&self) -> SourceLocation {
|
||||||
self.source_location
|
self.source_location
|
||||||
|
|
@ -2989,10 +3349,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)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct TargetInInstantiatedModule {
|
pub struct TargetInInstantiatedModuleOrGlobal {
|
||||||
pub instantiated_module: InstantiatedModule,
|
instantiated_module_or_global: InstantiatedModuleOrGlobal,
|
||||||
pub target: Target,
|
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)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod deduce_resets;
|
pub mod deduce_resets;
|
||||||
|
pub mod deduce_structural_eq_flags;
|
||||||
pub mod simplify_enums;
|
pub mod simplify_enums;
|
||||||
pub mod simplify_memories;
|
pub mod simplify_memories;
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
|
||||||
|
|
@ -1208,6 +1208,7 @@ impl<P: Pass> RunPass<P> for ExprEnum {
|
||||||
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
||||||
}
|
}
|
||||||
ExprEnum::ToTraceAsString(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::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
ExprEnum::Instance(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)),
|
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
|
|
@ -1215,6 +1216,10 @@ impl<P: Pass> RunPass<P> for ExprEnum {
|
||||||
ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args),
|
ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args),
|
||||||
ExprEnum::RegAsync(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::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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1649,6 +1654,35 @@ impl RunPassExpr for ops::ToTraceAsString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::with_flags(new_args[0], new_args[1], self.flags()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RunPassExpr for ModuleIO<CanonicalType> {
|
impl RunPassExpr for ModuleIO<CanonicalType> {
|
||||||
type Args<'a> = [Expr<CanonicalType>; 0];
|
type Args<'a> = [Expr<CanonicalType>; 0];
|
||||||
|
|
||||||
|
|
@ -1932,6 +1966,7 @@ impl_run_pass_copy!([] SVAttributeAnnotation);
|
||||||
impl_run_pass_copy!([] UInt);
|
impl_run_pass_copy!([] UInt);
|
||||||
impl_run_pass_copy!([] usize);
|
impl_run_pass_copy!([] usize);
|
||||||
impl_run_pass_copy!([] FormalKind);
|
impl_run_pass_copy!([] FormalKind);
|
||||||
|
impl_run_pass_copy!([] crate::formal::FormalInput);
|
||||||
impl_run_pass_copy!([] PhantomConst);
|
impl_run_pass_copy!([] PhantomConst);
|
||||||
|
|
||||||
macro_rules! impl_run_pass_for_struct {
|
macro_rules! impl_run_pass_for_struct {
|
||||||
|
|
@ -2248,6 +2283,12 @@ impl<P: Pass> RunPass<P> for TargetBase {
|
||||||
&TargetBase::RegAsync(v) => v.into(),
|
&TargetBase::RegAsync(v) => v.into(),
|
||||||
TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)),
|
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::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 {
|
Ok(reg.run_pass(pass_args)?.map(|reg| match reg {
|
||||||
AnyReg::Reg(reg) => TargetBase::Reg(reg),
|
AnyReg::Reg(reg) => TargetBase::Reg(reg),
|
||||||
|
|
|
||||||
1011
crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs
Normal file
1011
crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,28 +1,26 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{
|
use crate::{
|
||||||
array::{Array, ArrayType},
|
bundle::{BundleField, BundleType},
|
||||||
bundle::{Bundle, BundleField, BundleType},
|
enum_::{EnumType, EnumVariant},
|
||||||
enum_::{Enum, EnumType, EnumVariant},
|
|
||||||
expr::{
|
expr::{
|
||||||
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
|
ExprEnum,
|
||||||
ops::{self, EnumLiteral},
|
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
|
||||||
},
|
},
|
||||||
hdl,
|
|
||||||
int::UInt,
|
|
||||||
intern::{Intern, InternSlice, Interned, Memoize},
|
intern::{Intern, InternSlice, Interned, Memoize},
|
||||||
memory::{DynPortType, Mem, MemPort},
|
memory::{DynPortType, MemPort},
|
||||||
module::{
|
module::{
|
||||||
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
||||||
transform::visit::{Fold, Folder},
|
transform::{
|
||||||
|
deduce_structural_eq_flags::deduce_structural_eq_flags,
|
||||||
|
visit::{Fold, Folder},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
source_location::SourceLocation,
|
prelude::*,
|
||||||
ty::{CanonicalType, TraceAsString, Type},
|
|
||||||
util::HashMap,
|
util::HashMap,
|
||||||
wire::Wire,
|
|
||||||
};
|
};
|
||||||
use core::fmt;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SimplifyEnumsError {
|
pub enum SimplifyEnumsError {
|
||||||
|
|
@ -96,11 +94,13 @@ enum EnumTypeState {
|
||||||
|
|
||||||
struct ModuleState {
|
struct ModuleState {
|
||||||
module_name: NameId,
|
module_name: NameId,
|
||||||
|
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
||||||
|
source_location: SourceLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleState {
|
impl ModuleState {
|
||||||
fn gen_name(&mut self, name: &str) -> ScopedNameId {
|
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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,6 +109,45 @@ struct State {
|
||||||
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
module_state_stack: Vec<ModuleState>,
|
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 {
|
impl State {
|
||||||
|
|
@ -548,6 +587,185 @@ impl State {
|
||||||
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn handle_enum_structural_eq(
|
||||||
|
&mut self,
|
||||||
|
unfolded_ty: Enum,
|
||||||
|
folded_lhs: Expr<CanonicalType>,
|
||||||
|
folded_rhs: Expr<CanonicalType>,
|
||||||
|
flags: StructuralEqFlags,
|
||||||
|
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
||||||
|
if flags.assume_padding_is_zeroed {
|
||||||
|
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).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::with_flags(folded_lhs, folded_rhs, flags).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::with_flags(
|
||||||
|
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_lhs).tag),
|
||||||
|
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_rhs).tag),
|
||||||
|
StructuralEqFlags {
|
||||||
|
assume_padding_is_zeroed: 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, flags)?
|
||||||
|
} 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>,
|
||||||
|
flags: StructuralEqFlags,
|
||||||
|
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
||||||
|
if !contains_any_enum_types(unfolded_ty) {
|
||||||
|
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).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(),
|
||||||
|
flags,
|
||||||
|
)?;
|
||||||
|
retval = Some(match retval {
|
||||||
|
Some(old_eq) => old_eq & element_eq,
|
||||||
|
None => element_eq,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(retval.unwrap_or_else(|| {
|
||||||
|
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
CanonicalType::Enum(unfolded_ty) => {
|
||||||
|
self.handle_enum_structural_eq(unfolded_ty, folded_lhs, folded_rhs, flags)
|
||||||
|
}
|
||||||
|
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(),
|
||||||
|
flags,
|
||||||
|
)?;
|
||||||
|
retval = Some(match retval {
|
||||||
|
Some(old_eq) => old_eq & field_eq,
|
||||||
|
None => field_eq,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(retval.unwrap_or_else(|| {
|
||||||
|
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).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),
|
||||||
|
flags,
|
||||||
|
),
|
||||||
|
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(
|
fn connect_port(
|
||||||
|
|
@ -675,6 +893,8 @@ impl Folder for State {
|
||||||
fn fold_module<T: BundleType>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error> {
|
fn fold_module<T: BundleType>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error> {
|
||||||
self.module_state_stack.push(ModuleState {
|
self.module_state_stack.push(ModuleState {
|
||||||
module_name: v.name_id(),
|
module_name: v.name_id(),
|
||||||
|
expr_cache: HashMap::default(),
|
||||||
|
source_location: v.source_location(),
|
||||||
});
|
});
|
||||||
let retval = Fold::default_fold(v, self);
|
let retval = Fold::default_fold(v, self);
|
||||||
self.module_state_stack.pop();
|
self.module_state_stack.pop();
|
||||||
|
|
@ -682,30 +902,51 @@ impl Folder for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
|
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) => {
|
ExprEnum::EnumLiteral(op) => {
|
||||||
let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?;
|
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.ty(),
|
||||||
op.variant_index(),
|
op.variant_index(),
|
||||||
folded_variant_value,
|
folded_variant_value,
|
||||||
)?))
|
)?)
|
||||||
}
|
}
|
||||||
ExprEnum::VariantAccess(op) => {
|
ExprEnum::VariantAccess(op) => {
|
||||||
let folded_base_expr = Expr::canonical(op.base()).fold(self)?;
|
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(),
|
op.base().ty(),
|
||||||
folded_base_expr,
|
folded_base_expr,
|
||||||
op.variant_index(),
|
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.flags(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
ExprEnum::MemPort(mem_port) => {
|
||||||
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
||||||
ExprEnum::Wire(wire)
|
ExprEnum::Wire(wire)
|
||||||
} else {
|
} else {
|
||||||
ExprEnum::MemPort(mem_port.fold(self)?)
|
ExprEnum::MemPort(mem_port.fold(self)?)
|
||||||
},
|
}
|
||||||
),
|
}
|
||||||
ExprEnum::UIntLiteral(_)
|
ExprEnum::UIntLiteral(_)
|
||||||
| ExprEnum::SIntLiteral(_)
|
| ExprEnum::SIntLiteral(_)
|
||||||
| ExprEnum::BoolLiteral(_)
|
| ExprEnum::BoolLiteral(_)
|
||||||
|
|
@ -813,16 +1054,26 @@ impl Folder for State {
|
||||||
| ExprEnum::Wire(_)
|
| ExprEnum::Wire(_)
|
||||||
| ExprEnum::Reg(_)
|
| ExprEnum::Reg(_)
|
||||||
| ExprEnum::RegSync(_)
|
| 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> {
|
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 memories = vec![];
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
for memory in block.memories {
|
for memory in block.memories {
|
||||||
let old_element_ty = memory.array_type().element();
|
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 {
|
if new_element_ty != old_element_ty {
|
||||||
let mut new_ports = vec![];
|
let mut new_ports = vec![];
|
||||||
for port in memory.ports() {
|
for port in memory.ports() {
|
||||||
|
|
@ -848,7 +1099,7 @@ impl Folder for State {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let wire = Wire::new_unchecked(
|
let wire = Wire::new_unchecked(
|
||||||
self.module_state_stack
|
this.module_state_stack
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.gen_name(&format!(
|
.gen_name(&format!(
|
||||||
|
|
@ -872,7 +1123,7 @@ impl Folder for State {
|
||||||
Expr::canonical(wire.to_expr()),
|
Expr::canonical(wire.to_expr()),
|
||||||
port.source_location(),
|
port.source_location(),
|
||||||
);
|
);
|
||||||
self.replacement_mem_ports.insert(port, wire.canonical());
|
this.replacement_mem_ports.insert(port, wire.canonical());
|
||||||
}
|
}
|
||||||
memories.push(Mem::new_unchecked(
|
memories.push(Mem::new_unchecked(
|
||||||
memory.scoped_name(),
|
memory.scoped_name(),
|
||||||
|
|
@ -887,10 +1138,12 @@ impl Folder for State {
|
||||||
memory.mem_annotations(),
|
memory.mem_annotations(),
|
||||||
));
|
));
|
||||||
} else {
|
} 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 {
|
Ok(Block {
|
||||||
memories: Intern::intern_owned(memories),
|
memories: Intern::intern_owned(memories),
|
||||||
stmts: Intern::intern_owned(stmts),
|
stmts: Intern::intern_owned(stmts),
|
||||||
|
|
@ -1012,10 +1265,13 @@ pub fn simplify_enums(
|
||||||
module: Interned<Module<Bundle>>,
|
module: Interned<Module<Bundle>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
||||||
|
let module = deduce_structural_eq_flags(module);
|
||||||
module.fold(&mut State {
|
module.fold(&mut State {
|
||||||
enum_types: HashMap::default(),
|
enum_types: HashMap::default(),
|
||||||
replacement_mem_ports: HashMap::default(),
|
replacement_mem_ports: HashMap::default(),
|
||||||
kind,
|
kind,
|
||||||
module_state_stack: vec![],
|
module_state_stack: vec![],
|
||||||
|
new_prefix_stmts_for_block: vec![],
|
||||||
|
new_suffix_stmts_for_block: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ use crate::{
|
||||||
TargetPathTraceAsStringInner,
|
TargetPathTraceAsStringInner,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
formal::FormalKind,
|
formal::{FormalInput, FormalInputKind, FormalKind},
|
||||||
int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
|
int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
|
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
|
||||||
module::{
|
module::{
|
||||||
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
|
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,
|
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
|
||||||
StmtInstance, StmtMatch, StmtReg, StmtWire,
|
StmtInstance, StmtMatch, StmtReg, StmtWire,
|
||||||
},
|
},
|
||||||
|
|
@ -482,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"));
|
include!(concat!(env!("OUT_DIR"), "/visit.rs"));
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ pub use crate::{
|
||||||
ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat,
|
ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat,
|
||||||
},
|
},
|
||||||
formal::{
|
formal::{
|
||||||
MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset,
|
all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert,
|
||||||
hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
|
hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
|
||||||
hdl_cover_with_enable,
|
hdl_cover_with_enable,
|
||||||
},
|
},
|
||||||
hdl, hdl_module,
|
hdl, hdl_module,
|
||||||
|
|
@ -37,7 +37,7 @@ pub use crate::{
|
||||||
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
|
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
|
||||||
},
|
},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
testing::{FormalMode, assert_formal},
|
testing::{FormalMode, assert_formal, checked_vcd_output},
|
||||||
ty::{AsMask, CanonicalType, TraceAsString, Type},
|
ty::{AsMask, CanonicalType, TraceAsString, Type},
|
||||||
util::{ConstUsize, GenericConstUsize},
|
util::{ConstUsize, GenericConstUsize},
|
||||||
wire::Wire,
|
wire::Wire,
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
|
||||||
if let Some(init) = init {
|
if let Some(init) = init {
|
||||||
assert_eq!(ty, init.ty(), "register's type must match init type");
|
assert_eq!(ty, init.ty(), "register's type must match init type");
|
||||||
}
|
}
|
||||||
|
scoped_name.0.assert_is_name_id();
|
||||||
Self {
|
Self {
|
||||||
name: scoped_name,
|
name: scoped_name,
|
||||||
source_location,
|
source_location,
|
||||||
|
|
@ -94,7 +95,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
|
||||||
self.containing_module_name_id().0
|
self.containing_module_name_id().0
|
||||||
}
|
}
|
||||||
pub fn containing_module_name_id(&self) -> NameId {
|
pub fn containing_module_name_id(&self) -> NameId {
|
||||||
self.name.0
|
self.name.0.unwrap_name_id()
|
||||||
}
|
}
|
||||||
pub fn name(&self) -> Interned<str> {
|
pub fn name(&self) -> Interned<str> {
|
||||||
self.name_id().0
|
self.name_id().0
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,29 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{BundleField, BundleType},
|
bundle::{BundleField, BundleType},
|
||||||
expr::{
|
expr::{
|
||||||
Flow,
|
ExprEnum, Flow,
|
||||||
|
ops::SimIoForGlobal,
|
||||||
target::{
|
target::{
|
||||||
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
GetTarget, Target, TargetBase, TargetChild, TargetPathArrayElement,
|
||||||
TargetPathTraceAsStringInner,
|
TargetPathBundleField, TargetPathElement, TargetPathTraceAsStringInner,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
formal::FormalInput,
|
||||||
int::BoolOrIntType,
|
int::BoolOrIntType,
|
||||||
intern::{
|
intern::{
|
||||||
Intern, InternSlice, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId,
|
Intern, InternSlice, Interned, InternedCompare, InternedSliceIter, Memoize,
|
||||||
|
PtrEqWithTypeId, SupportsPtrEqWithTypeId,
|
||||||
},
|
},
|
||||||
module::{
|
module::{
|
||||||
ModuleIO,
|
ModuleIO, StmtFormal,
|
||||||
transform::visit::{Fold, Folder, Visit, Visitor},
|
transform::visit::{Fold, Folder, Visit, Visitor},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
reset::ResetType,
|
reset::ResetType,
|
||||||
sim::{
|
sim::{
|
||||||
compiler::{
|
compiler::{
|
||||||
Compiled, CompiledBundleField, CompiledExternModule, CompiledTypeLayoutBody,
|
Compiled, CompiledAssert, CompiledBundleField, CompiledExternModule,
|
||||||
CompiledValue, ExternModuleClockForPast,
|
CompiledTypeLayoutBody, CompiledValue, ExternModuleClockForPast,
|
||||||
},
|
},
|
||||||
interpreter::{
|
interpreter::{
|
||||||
BreakAction, BreakpointsSet, RunResult, SmallUInt, State,
|
BreakAction, BreakpointsSet, RunResult, SmallUInt, State,
|
||||||
|
|
@ -50,7 +53,7 @@ use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
fmt,
|
fmt::{self, Write},
|
||||||
future::{Future, IntoFuture},
|
future::{Future, IntoFuture},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
mem,
|
mem,
|
||||||
|
|
@ -315,6 +318,14 @@ impl_trace_decl! {
|
||||||
ty: CanonicalType,
|
ty: CanonicalType,
|
||||||
flow: Flow,
|
flow: Flow,
|
||||||
}),
|
}),
|
||||||
|
FormalInput(TraceFormalInput {
|
||||||
|
fn children(self) -> _ {
|
||||||
|
[*self.child].intern_slice()
|
||||||
|
}
|
||||||
|
name: Interned<str>,
|
||||||
|
child: Interned<TraceDecl>,
|
||||||
|
formal_input: FormalInput,
|
||||||
|
}),
|
||||||
Bundle(TraceBundle {
|
Bundle(TraceBundle {
|
||||||
fn children(self) -> _ {
|
fn children(self) -> _ {
|
||||||
self.fields
|
self.fields
|
||||||
|
|
@ -1288,9 +1299,14 @@ impl SimulationModuleState {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn get_io(
|
fn get_io(
|
||||||
&self,
|
&self,
|
||||||
mut target: Target,
|
target: &mut Interned<Target>,
|
||||||
which_module: WhichModule,
|
which_module: WhichModule<'_>,
|
||||||
) -> CompiledValue<CanonicalType> {
|
) -> CompiledValue<CanonicalType> {
|
||||||
|
match which_module {
|
||||||
|
WhichModule::Main { global_io } => *target = global_io.to_sim_io_target(*target),
|
||||||
|
WhichModule::Extern { .. } => {}
|
||||||
|
}
|
||||||
|
let mut target = **target;
|
||||||
assert!(
|
assert!(
|
||||||
target.canonical_ty().is_passive(),
|
target.canonical_ty().is_passive(),
|
||||||
"simulator read/write expression must have a passive type \
|
"simulator read/write expression must have a passive type \
|
||||||
|
|
@ -1317,9 +1333,9 @@ impl SimulationModuleState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => panic!(
|
WhichModule::Main { .. } => panic!(
|
||||||
"simulator read/write expression must be \
|
"simulator read/write expression must be \
|
||||||
an array element/field of `Simulation::io()`"
|
an array element/field of `Simulation::io()` or `Simulation::global_io()`"
|
||||||
),
|
),
|
||||||
WhichModule::Extern { .. } => panic!(
|
WhichModule::Extern { .. } => panic!(
|
||||||
"simulator read/write expression must be \
|
"simulator read/write expression must be \
|
||||||
|
|
@ -1329,18 +1345,18 @@ impl SimulationModuleState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule) -> bool {
|
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule<'_>) -> bool {
|
||||||
let Some(target) = io.target() else {
|
let Some(mut target) = io.target() else {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => panic!(
|
WhichModule::Main { .. } => panic!(
|
||||||
"can't read from an expression that's not a field/element of `Simulation::io()`"
|
"can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
|
||||||
),
|
),
|
||||||
WhichModule::Extern { .. } => panic!(
|
WhichModule::Extern { .. } => panic!(
|
||||||
"can't read from an expression that's not based on one of this module's inputs/outputs"
|
"can't read from an expression that's not based on one of this module's inputs/outputs"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match self.get_io(*target, which_module).layout.ty {
|
match self.get_io(&mut target, which_module).layout.ty {
|
||||||
CanonicalType::UInt(_)
|
CanonicalType::UInt(_)
|
||||||
| CanonicalType::SInt(_)
|
| CanonicalType::SInt(_)
|
||||||
| CanonicalType::Bool(_)
|
| CanonicalType::Bool(_)
|
||||||
|
|
@ -1360,24 +1376,24 @@ impl SimulationModuleState {
|
||||||
fn read_helper_current(
|
fn read_helper_current(
|
||||||
&self,
|
&self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
which_module: WhichModule,
|
which_module: WhichModule<'_>,
|
||||||
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
|
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
|
||||||
let Some(target) = io.target() else {
|
let Some(mut target) = io.target() else {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => panic!(
|
WhichModule::Main { .. } => panic!(
|
||||||
"can't read from an expression that's not a field/element of `Simulation::io()`"
|
"can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
|
||||||
),
|
),
|
||||||
WhichModule::Extern { .. } => panic!(
|
WhichModule::Extern { .. } => panic!(
|
||||||
"can't read from an expression that's not based on one of this module's inputs/outputs"
|
"can't read from an expression that's not based on one of this module's inputs/outputs"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let compiled_value = self.get_io(*target, which_module);
|
let compiled_value = self.get_io(&mut target, which_module);
|
||||||
match target.flow() {
|
match target.flow() {
|
||||||
Flow::Source => {
|
Flow::Source => {
|
||||||
if !self.uninitialized_ios.is_empty() {
|
if !self.uninitialized_ios.is_empty() {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => {
|
WhichModule::Main { .. } => {
|
||||||
panic!(
|
panic!(
|
||||||
"can't read from an output before initializing all inputs\nuninitialized_ios={:#?}",
|
"can't read from an output before initializing all inputs\nuninitialized_ios={:#?}",
|
||||||
SortedSetDebug(&self.uninitialized_ios),
|
SortedSetDebug(&self.uninitialized_ios),
|
||||||
|
|
@ -1396,7 +1412,9 @@ impl SimulationModuleState {
|
||||||
Flow::Sink => {
|
Flow::Sink => {
|
||||||
if self.uninitialized_ios.contains_key(&*target) {
|
if self.uninitialized_ios.contains_key(&*target) {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => panic!("can't read from an uninitialized input"),
|
WhichModule::Main { .. } => {
|
||||||
|
panic!("can't read from an uninitialized input")
|
||||||
|
}
|
||||||
WhichModule::Extern { .. } => {
|
WhichModule::Extern { .. } => {
|
||||||
panic!("can't read from an uninitialized output");
|
panic!("can't read from an uninitialized output");
|
||||||
}
|
}
|
||||||
|
|
@ -1412,7 +1430,7 @@ impl SimulationModuleState {
|
||||||
&self,
|
&self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
read_time: ReadTime,
|
read_time: ReadTime,
|
||||||
which_module: WhichModule,
|
which_module: WhichModule<'_>,
|
||||||
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
|
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
|
||||||
match read_time {
|
match read_time {
|
||||||
ReadTime::Current => self.read_helper_current(io, which_module),
|
ReadTime::Current => self.read_helper_current(io, which_module),
|
||||||
|
|
@ -1438,22 +1456,22 @@ impl SimulationModuleState {
|
||||||
fn write_helper(
|
fn write_helper(
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
which_module: WhichModule,
|
which_module: WhichModule<'_>,
|
||||||
) -> CompiledValue<CanonicalType> {
|
) -> CompiledValue<CanonicalType> {
|
||||||
let Some(target) = io.target() else {
|
let Some(mut target) = io.target() else {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => panic!(
|
WhichModule::Main { .. } => panic!(
|
||||||
"can't write to an expression that's not a field/element of `Simulation::io()`"
|
"can't write to an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
|
||||||
),
|
),
|
||||||
WhichModule::Extern { .. } => panic!(
|
WhichModule::Extern { .. } => panic!(
|
||||||
"can't write to an expression that's not based on one of this module's outputs"
|
"can't write to an expression that's not based on one of this module's outputs"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let compiled_value = self.get_io(*target, which_module);
|
let compiled_value = self.get_io(&mut target, which_module);
|
||||||
match target.flow() {
|
match target.flow() {
|
||||||
Flow::Source => match which_module {
|
Flow::Source => match which_module {
|
||||||
WhichModule::Main => panic!("can't write to an output"),
|
WhichModule::Main { .. } => panic!("can't write to an output"),
|
||||||
WhichModule::Extern { .. } => panic!("can't write to an input"),
|
WhichModule::Extern { .. } => panic!("can't write to an input"),
|
||||||
},
|
},
|
||||||
Flow::Sink => {}
|
Flow::Sink => {}
|
||||||
|
|
@ -1573,9 +1591,9 @@ impl fmt::Debug for SimulationExternModuleState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone)]
|
||||||
enum WhichModule {
|
enum WhichModule<'a> {
|
||||||
Main,
|
Main { global_io: &'a SimulationGlobalIo },
|
||||||
Extern { module_index: usize },
|
Extern { module_index: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1986,6 +2004,7 @@ impl SensitivitySet {
|
||||||
struct SimulationImpl {
|
struct SimulationImpl {
|
||||||
state: interpreter::State,
|
state: interpreter::State,
|
||||||
io: Expr<Bundle>,
|
io: Expr<Bundle>,
|
||||||
|
global_io: SimulationGlobalIo,
|
||||||
main_module: SimulationModuleState,
|
main_module: SimulationModuleState,
|
||||||
extern_modules: Box<[SimulationExternModuleState]>,
|
extern_modules: Box<[SimulationExternModuleState]>,
|
||||||
trace_decls: TraceModule,
|
trace_decls: TraceModule,
|
||||||
|
|
@ -2005,6 +2024,7 @@ struct SimulationImpl {
|
||||||
>,
|
>,
|
||||||
waiting_sensitivity_sets_by_address: HashMap<*const SensitivitySet, Rc<SensitivitySet>>,
|
waiting_sensitivity_sets_by_address: HashMap<*const SensitivitySet, Rc<SensitivitySet>>,
|
||||||
trace_as_string_buf: String,
|
trace_as_string_buf: String,
|
||||||
|
asserts: Interned<[CompiledAssert]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for SimulationImpl {
|
impl fmt::Debug for SimulationImpl {
|
||||||
|
|
@ -2082,6 +2102,7 @@ impl SimulationImpl {
|
||||||
let Self {
|
let Self {
|
||||||
state,
|
state,
|
||||||
io: self_io,
|
io: self_io,
|
||||||
|
global_io,
|
||||||
main_module,
|
main_module,
|
||||||
extern_modules,
|
extern_modules,
|
||||||
trace_decls,
|
trace_decls,
|
||||||
|
|
@ -2095,10 +2116,15 @@ impl SimulationImpl {
|
||||||
waiting_sensitivity_sets_by_compiled_value,
|
waiting_sensitivity_sets_by_compiled_value,
|
||||||
waiting_sensitivity_sets_by_address,
|
waiting_sensitivity_sets_by_address,
|
||||||
trace_as_string_buf: _,
|
trace_as_string_buf: _,
|
||||||
|
asserts,
|
||||||
} = self;
|
} = self;
|
||||||
f.debug_struct("Simulation")
|
f.debug_struct("Simulation")
|
||||||
.field("state", state)
|
.field("state", state)
|
||||||
.field("io", io.unwrap_or(self_io))
|
.field("io", io.unwrap_or(self_io))
|
||||||
|
.field(
|
||||||
|
"global_io",
|
||||||
|
&fmt::from_fn(|f| f.debug_map().entries(global_io.global_io).finish()),
|
||||||
|
)
|
||||||
.field("main_module", main_module)
|
.field("main_module", main_module)
|
||||||
.field("extern_modules", extern_modules)
|
.field("extern_modules", extern_modules)
|
||||||
.field("trace_decls", trace_decls)
|
.field("trace_decls", trace_decls)
|
||||||
|
|
@ -2118,6 +2144,7 @@ impl SimulationImpl {
|
||||||
"waiting_sensitivity_sets_by_compiled_value",
|
"waiting_sensitivity_sets_by_compiled_value",
|
||||||
&DebugSensitivitySetsByCompiledValue(waiting_sensitivity_sets_by_compiled_value),
|
&DebugSensitivitySetsByCompiledValue(waiting_sensitivity_sets_by_compiled_value),
|
||||||
)
|
)
|
||||||
|
.field("asserts", asserts)
|
||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
fn new(compiled: Compiled<Bundle>) -> Self {
|
fn new(compiled: Compiled<Bundle>) -> Self {
|
||||||
|
|
@ -2160,22 +2187,29 @@ impl SimulationImpl {
|
||||||
Self {
|
Self {
|
||||||
state: State::new(compiled.insns),
|
state: State::new(compiled.insns),
|
||||||
io: compiled.io.to_expr(),
|
io: compiled.io.to_expr(),
|
||||||
|
global_io: SimulationGlobalIo::new(compiled.global_io),
|
||||||
main_module: SimulationModuleState::new(
|
main_module: SimulationModuleState::new(
|
||||||
compiled
|
compiled
|
||||||
.io
|
.global_io
|
||||||
.ty()
|
.iter()
|
||||||
.fields()
|
.map(|&(global_io, value)| (global_io.into(), value))
|
||||||
.into_iter()
|
.chain(
|
||||||
.zip(compiled.base_module.module_io)
|
compiled
|
||||||
.map(|(BundleField { name, .. }, value)| {
|
.io
|
||||||
(
|
.ty()
|
||||||
io_target.join(
|
.fields()
|
||||||
TargetPathElement::from(TargetPathBundleField { name })
|
.into_iter()
|
||||||
.intern_sized(),
|
.zip(compiled.base_module.module_io)
|
||||||
),
|
.map(|(BundleField { name, .. }, value)| {
|
||||||
value,
|
(
|
||||||
)
|
io_target.join(
|
||||||
}),
|
TargetPathElement::from(TargetPathBundleField { name })
|
||||||
|
.intern_sized(),
|
||||||
|
),
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
&[],
|
&[],
|
||||||
),
|
),
|
||||||
extern_modules,
|
extern_modules,
|
||||||
|
|
@ -2202,6 +2236,7 @@ impl SimulationImpl {
|
||||||
waiting_sensitivity_sets_by_compiled_value: HashMap::default(),
|
waiting_sensitivity_sets_by_compiled_value: HashMap::default(),
|
||||||
waiting_sensitivity_sets_by_address: HashMap::default(),
|
waiting_sensitivity_sets_by_address: HashMap::default(),
|
||||||
trace_as_string_buf: String::with_capacity(256),
|
trace_as_string_buf: String::with_capacity(256),
|
||||||
|
asserts: compiled.asserts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn write_traces<const ONLY_IF_CHANGED: bool>(
|
fn write_traces<const ONLY_IF_CHANGED: bool>(
|
||||||
|
|
@ -2729,6 +2764,50 @@ impl SimulationImpl {
|
||||||
self.cancel_wake_after_change(&sensitivity_set);
|
self.cancel_wake_after_change(&sensitivity_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[track_caller]
|
||||||
|
#[cold]
|
||||||
|
fn handle_failed_asserts(&mut self, assert_failed_log: Vec<usize>) -> ! {
|
||||||
|
let mut message = format!(
|
||||||
|
"Assertions/Assumptions failed at time {:?}:\n",
|
||||||
|
self.event_queue.lock().instant,
|
||||||
|
);
|
||||||
|
for assert_failed_index in assert_failed_log {
|
||||||
|
let CompiledAssert {
|
||||||
|
instantiated_module,
|
||||||
|
stmt_formal:
|
||||||
|
StmtFormal {
|
||||||
|
kind,
|
||||||
|
clk: _,
|
||||||
|
pred: _,
|
||||||
|
en: _,
|
||||||
|
text,
|
||||||
|
source_location,
|
||||||
|
},
|
||||||
|
} = self.asserts[assert_failed_index];
|
||||||
|
writeln!(
|
||||||
|
message,
|
||||||
|
"at {source_location}: in {instantiated_module:?}: {} failed: {text}",
|
||||||
|
kind.as_str()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
panic!("{message}")
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn check_for_failed_asserts(&mut self) {
|
||||||
|
if self.state.assert_failed_log.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(Event {
|
||||||
|
instant: _,
|
||||||
|
kind: EventKind::State,
|
||||||
|
}) = self.event_queue.peek_first_event_for_now()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let assert_failed_log = mem::take(&mut self.state.assert_failed_log);
|
||||||
|
self.handle_failed_asserts(assert_failed_log);
|
||||||
|
}
|
||||||
fn write_traces_after_event(&mut self) {
|
fn write_traces_after_event(&mut self) {
|
||||||
if let Some(Event {
|
if let Some(Event {
|
||||||
instant: _,
|
instant: _,
|
||||||
|
|
@ -2831,6 +2910,7 @@ impl SimulationImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.write_traces_after_event();
|
this.write_traces_after_event();
|
||||||
|
this.check_for_failed_asserts();
|
||||||
this.check_waiting_sensitivity_sets();
|
this.check_waiting_sensitivity_sets();
|
||||||
} else {
|
} else {
|
||||||
event_queue = first_entry.into_event_queue_lock();
|
event_queue = first_entry.into_event_queue_lock();
|
||||||
|
|
@ -2852,18 +2932,23 @@ impl SimulationImpl {
|
||||||
fn settle(this_ref: &Rc<RefCell<Self>>) {
|
fn settle(this_ref: &Rc<RefCell<Self>>) {
|
||||||
Self::run_until(this_ref, &mut Some);
|
Self::run_until(this_ref, &mut Some);
|
||||||
}
|
}
|
||||||
fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState {
|
fn get_module(&self, which_module: WhichModule<'_>) -> &SimulationModuleState {
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => &self.main_module,
|
WhichModule::Main { .. } => &self.main_module,
|
||||||
WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state,
|
WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState {
|
fn get_module_mut_and_which_module(
|
||||||
|
&mut self,
|
||||||
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
|
) -> (&mut SimulationModuleState, WhichModule<'_>) {
|
||||||
|
let which_module = which_module(&self.global_io);
|
||||||
match which_module {
|
match which_module {
|
||||||
WhichModule::Main => &mut self.main_module,
|
WhichModule::Main { .. } => (&mut self.main_module, which_module),
|
||||||
WhichModule::Extern { module_index } => {
|
WhichModule::Extern { module_index } => (
|
||||||
&mut self.extern_modules[module_index].module_state
|
&mut self.extern_modules[module_index].module_state,
|
||||||
}
|
which_module,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|
@ -2871,18 +2956,23 @@ impl SimulationImpl {
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
read_time: ReadTime,
|
read_time: ReadTime,
|
||||||
which_module: WhichModule,
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
) -> MaybeNeedsSettle<ReadBitFn, bool> {
|
) -> MaybeNeedsSettle<ReadBitFn, bool> {
|
||||||
|
let which_module = which_module(&self.global_io);
|
||||||
self.get_module(which_module)
|
self.get_module(which_module)
|
||||||
.read_helper(Expr::canonical(io), read_time, which_module)
|
.read_helper(Expr::canonical(io), read_time, which_module)
|
||||||
.map(|compiled_value| ReadBitFn { compiled_value })
|
.map(|compiled_value| ReadBitFn { compiled_value })
|
||||||
.apply_no_settle(&mut self.state)
|
.apply_no_settle(&mut self.state)
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn write_bit(&mut self, io: Expr<CanonicalType>, value: bool, which_module: WhichModule) {
|
fn write_bit(
|
||||||
let compiled_value = self
|
&mut self,
|
||||||
.get_module_mut(which_module)
|
io: Expr<CanonicalType>,
|
||||||
.write_helper(io, which_module);
|
value: bool,
|
||||||
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
|
) {
|
||||||
|
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
|
||||||
|
let compiled_value = module.write_helper(io, which_module);
|
||||||
self.event_queue.add_event_for_now(EventKind::State);
|
self.event_queue.add_event_for_now(EventKind::State);
|
||||||
match compiled_value.range.len().as_single() {
|
match compiled_value.range.len().as_single() {
|
||||||
Some(TypeLenSingle::SmallSlot) => {
|
Some(TypeLenSingle::SmallSlot) => {
|
||||||
|
|
@ -2900,8 +2990,9 @@ impl SimulationImpl {
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<I>,
|
io: Expr<I>,
|
||||||
read_time: ReadTime,
|
read_time: ReadTime,
|
||||||
which_module: WhichModule,
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
) -> MaybeNeedsSettle<ReadBoolOrIntFn<I>, I::Value> {
|
) -> MaybeNeedsSettle<ReadBoolOrIntFn<I>, I::Value> {
|
||||||
|
let which_module = which_module(&self.global_io);
|
||||||
self.get_module(which_module)
|
self.get_module(which_module)
|
||||||
.read_helper(Expr::canonical(io), read_time, which_module)
|
.read_helper(Expr::canonical(io), read_time, which_module)
|
||||||
.map(|compiled_value| ReadBoolOrIntFn { compiled_value, io })
|
.map(|compiled_value| ReadBoolOrIntFn { compiled_value, io })
|
||||||
|
|
@ -2912,11 +3003,10 @@ impl SimulationImpl {
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<I>,
|
io: Expr<I>,
|
||||||
value: I::Value,
|
value: I::Value,
|
||||||
which_module: WhichModule,
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
) {
|
) {
|
||||||
let compiled_value = self
|
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
|
||||||
.get_module_mut(which_module)
|
let compiled_value = module.write_helper(Expr::canonical(io), which_module);
|
||||||
.write_helper(Expr::canonical(io), which_module);
|
|
||||||
self.event_queue.add_event_for_now(EventKind::State);
|
self.event_queue.add_event_for_now(EventKind::State);
|
||||||
let value: BigInt = value.into();
|
let value: BigInt = value.into();
|
||||||
match compiled_value.range.len().as_single() {
|
match compiled_value.range.len().as_single() {
|
||||||
|
|
@ -3148,7 +3238,12 @@ impl SimulationImpl {
|
||||||
any_change.get()
|
any_change.get()
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule) -> bool {
|
fn is_reset_async(
|
||||||
|
&self,
|
||||||
|
io: Expr<CanonicalType>,
|
||||||
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
|
) -> bool {
|
||||||
|
let which_module = which_module(&self.global_io);
|
||||||
self.get_module(which_module)
|
self.get_module(which_module)
|
||||||
.is_reset_async(io, which_module)
|
.is_reset_async(io, which_module)
|
||||||
}
|
}
|
||||||
|
|
@ -3157,11 +3252,12 @@ impl SimulationImpl {
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
read_time: ReadTime,
|
read_time: ReadTime,
|
||||||
which_module: WhichModule,
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
) -> (
|
) -> (
|
||||||
CompiledValue<CanonicalType>,
|
CompiledValue<CanonicalType>,
|
||||||
MaybeNeedsSettle<ReadFn, SimValue<CanonicalType>>,
|
MaybeNeedsSettle<ReadFn, SimValue<CanonicalType>>,
|
||||||
) {
|
) {
|
||||||
|
let which_module = which_module(&self.global_io);
|
||||||
let compiled_value = self
|
let compiled_value = self
|
||||||
.get_module(which_module)
|
.get_module(which_module)
|
||||||
.read_helper(io, read_time, which_module);
|
.read_helper(io, read_time, which_module);
|
||||||
|
|
@ -3189,11 +3285,10 @@ impl SimulationImpl {
|
||||||
&mut self,
|
&mut self,
|
||||||
io: Expr<CanonicalType>,
|
io: Expr<CanonicalType>,
|
||||||
value: &SimValue<CanonicalType>,
|
value: &SimValue<CanonicalType>,
|
||||||
which_module: WhichModule,
|
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
|
||||||
) {
|
) {
|
||||||
let compiled_value = self
|
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
|
||||||
.get_module_mut(which_module)
|
let compiled_value = module.write_helper(io, which_module);
|
||||||
.write_helper(io, which_module);
|
|
||||||
self.event_queue.add_event_for_now(EventKind::State);
|
self.event_queue.add_event_for_now(EventKind::State);
|
||||||
assert_eq!(io.ty(), value.ty());
|
assert_eq!(io.ty(), value.ty());
|
||||||
Self::read_write_sim_value_helper(
|
Self::read_write_sim_value_helper(
|
||||||
|
|
@ -3370,6 +3465,318 @@ impl Drop for SimulationImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SimulationGlobalIo {
|
||||||
|
global_io: Interned<[(SimIoForGlobal, CompiledValue<CanonicalType>)]>,
|
||||||
|
global_io_map: Rc<HashMap<SimIoForGlobal, usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SimulationGlobalIo {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
global_io: Interned::default(),
|
||||||
|
global_io_map: Rc::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimulationGlobalIo {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_map().entries(self.global_io).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimulationGlobalIo {
|
||||||
|
fn new(global_io: Interned<[(SimIoForGlobal, CompiledValue<CanonicalType>)]>) -> Self {
|
||||||
|
Self {
|
||||||
|
global_io,
|
||||||
|
global_io_map: Rc::new(HashMap::from_iter(
|
||||||
|
global_io
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, &(global, _))| (global, index)),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn iter(&self) -> SimulationGlobalIoIter {
|
||||||
|
SimulationGlobalIoIter {
|
||||||
|
global_io: self.global_io.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn globals(&self) -> SimulationGlobalIoGlobalsIter {
|
||||||
|
SimulationGlobalIoGlobalsIter {
|
||||||
|
global_io: self.global_io.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn exprs(&self) -> SimulationGlobalIoExprsIter {
|
||||||
|
SimulationGlobalIoExprsIter {
|
||||||
|
global_io: self.global_io.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.global_io.len()
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn contains(&self, global: FormalInput) -> bool {
|
||||||
|
self.global_io_map
|
||||||
|
.contains_key(&SimIoForGlobal::new(global))
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self, global: FormalInput) -> Option<Expr<CanonicalType>> {
|
||||||
|
self.contains(global)
|
||||||
|
.then(|| SimIoForGlobal::new(global).to_expr())
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn expr_to_global(&self, expr: Expr<CanonicalType>) -> Option<FormalInput> {
|
||||||
|
let global = match *Expr::expr_enum(expr) {
|
||||||
|
ExprEnum::FormalInput(global) => global,
|
||||||
|
ExprEnum::SimIoForGlobal(expr) => expr.global(),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
self.global_io_map
|
||||||
|
.contains_key(&SimIoForGlobal::new(global))
|
||||||
|
.then_some(global)
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
fn to_sim_io_target(&self, target: Interned<Target>) -> Interned<Target> {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct FormalInputExprToSimIoExpr;
|
||||||
|
impl Memoize for FormalInputExprToSimIoExpr {
|
||||||
|
type Input = Interned<Target>;
|
||||||
|
type InputOwned = Interned<Target>;
|
||||||
|
type Output = Interned<Target>;
|
||||||
|
|
||||||
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||||
|
match **input {
|
||||||
|
Target::Base(base) => match *base {
|
||||||
|
TargetBase::ModuleIO(_)
|
||||||
|
| TargetBase::MemPort(_)
|
||||||
|
| TargetBase::Reg(_)
|
||||||
|
| TargetBase::RegSync(_)
|
||||||
|
| TargetBase::RegAsync(_)
|
||||||
|
| TargetBase::Wire(_)
|
||||||
|
| TargetBase::Instance(_)
|
||||||
|
| TargetBase::SimIoForGlobal(_) => *input,
|
||||||
|
TargetBase::FormalInput(global) => {
|
||||||
|
Target::from(SimIoForGlobal::new(global)).intern()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Target::Child(child) => Target::Child(TargetChild::new(
|
||||||
|
self.get_owned(child.parent()),
|
||||||
|
child.path_element(),
|
||||||
|
))
|
||||||
|
.intern_sized(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match *target.base() {
|
||||||
|
TargetBase::ModuleIO(_)
|
||||||
|
| TargetBase::MemPort(_)
|
||||||
|
| TargetBase::Reg(_)
|
||||||
|
| TargetBase::RegSync(_)
|
||||||
|
| TargetBase::RegAsync(_)
|
||||||
|
| TargetBase::Wire(_)
|
||||||
|
| TargetBase::Instance(_)
|
||||||
|
| TargetBase::SimIoForGlobal(_) => target,
|
||||||
|
TargetBase::FormalInput(global) => {
|
||||||
|
if self.contains(global) {
|
||||||
|
FormalInputExprToSimIoExpr.get_owned(target)
|
||||||
|
} else {
|
||||||
|
target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for SimulationGlobalIo {
|
||||||
|
type Item = (FormalInput, Expr<CanonicalType>);
|
||||||
|
type IntoIter = SimulationGlobalIoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for &'_ SimulationGlobalIo {
|
||||||
|
type Item = (FormalInput, Expr<CanonicalType>);
|
||||||
|
type IntoIter = SimulationGlobalIoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for &'_ mut SimulationGlobalIo {
|
||||||
|
type Item = (FormalInput, Expr<CanonicalType>);
|
||||||
|
type IntoIter = SimulationGlobalIoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_simulation_global_io_iter {
|
||||||
|
(
|
||||||
|
impl $SimulationGlobalIoIter:ident {
|
||||||
|
fn $global_io_to_item:ident(
|
||||||
|
$global_io_to_item_arg:ident: (SimIoForGlobal, CompiledValue<CanonicalType>),
|
||||||
|
) -> $item_ty:ty
|
||||||
|
$global_io_to_item_block:block
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct $SimulationGlobalIoIter {
|
||||||
|
global_io: InternedSliceIter<(SimIoForGlobal, CompiledValue<CanonicalType>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $SimulationGlobalIoIter {
|
||||||
|
fn $global_io_to_item(
|
||||||
|
$global_io_to_item_arg: (SimIoForGlobal, CompiledValue<CanonicalType>),
|
||||||
|
) -> $item_ty
|
||||||
|
$global_io_to_item_block
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for $SimulationGlobalIoIter {
|
||||||
|
type Item = $item_ty;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.global_io.next().map(Self::global_io_to_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.global_io.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.global_io.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(mut self) -> Option<Self::Item> {
|
||||||
|
self.next_back()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.global_io.nth(n).map(Self::global_io_to_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, init: B, f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
self.global_io.map(Self::global_io_to_item).fold(init, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::iter::FusedIterator for $SimulationGlobalIoIter {}
|
||||||
|
|
||||||
|
impl DoubleEndedIterator for $SimulationGlobalIoIter {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.global_io.next_back().map(Self::global_io_to_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.global_io.nth_back(n).map(Self::global_io_to_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rfold<B, F>(self, init: B, f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
self.global_io.map(Self::global_io_to_item).rfold(init, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExactSizeIterator for $SimulationGlobalIoIter {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
make_simulation_global_io_iter! {
|
||||||
|
impl SimulationGlobalIoIter {
|
||||||
|
fn global_io_to_item(
|
||||||
|
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
|
||||||
|
) -> (FormalInput, Expr<CanonicalType>) {
|
||||||
|
let (global, _) = v;
|
||||||
|
(global.global(), global.to_expr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimulationGlobalIoIter {
|
||||||
|
#[must_use]
|
||||||
|
pub fn globals(self) -> SimulationGlobalIoGlobalsIter {
|
||||||
|
SimulationGlobalIoGlobalsIter {
|
||||||
|
global_io: self.global_io,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn exprs(self) -> SimulationGlobalIoExprsIter {
|
||||||
|
SimulationGlobalIoExprsIter {
|
||||||
|
global_io: self.global_io,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimulationGlobalIoIter {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("SimulationGlobalIoIter")
|
||||||
|
.field(&fmt::from_fn(|f| {
|
||||||
|
f.debug_map().entries(self.clone()).finish()
|
||||||
|
}))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
make_simulation_global_io_iter! {
|
||||||
|
impl SimulationGlobalIoGlobalsIter {
|
||||||
|
fn global_io_to_item(
|
||||||
|
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
|
||||||
|
) -> FormalInput {
|
||||||
|
let (global, _) = v;
|
||||||
|
global.global()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimulationGlobalIoGlobalsIter {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("SimulationGlobalIoGlobalsIter")
|
||||||
|
.field(&fmt::from_fn(|f| {
|
||||||
|
f.debug_set().entries(self.clone()).finish()
|
||||||
|
}))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
make_simulation_global_io_iter! {
|
||||||
|
impl SimulationGlobalIoExprsIter {
|
||||||
|
fn global_io_to_item(
|
||||||
|
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
|
||||||
|
) -> Expr<CanonicalType> {
|
||||||
|
let (global, _) = v;
|
||||||
|
global.to_expr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimulationGlobalIoExprsIter {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("SimulationGlobalIoExprsIter")
|
||||||
|
.field(&fmt::from_fn(|f| {
|
||||||
|
f.debug_set().entries(self.clone()).finish()
|
||||||
|
}))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Simulation<T: BundleType> {
|
pub struct Simulation<T: BundleType> {
|
||||||
sim_impl: Rc<RefCell<SimulationImpl>>,
|
sim_impl: Rc<RefCell<SimulationImpl>>,
|
||||||
io: Expr<T>,
|
io: Expr<T>,
|
||||||
|
|
@ -3444,14 +3851,15 @@ macro_rules! impl_simulation_methods {
|
||||||
(
|
(
|
||||||
async_await = ($($async:tt, $await:tt)?),
|
async_await = ($($async:tt, $await:tt)?),
|
||||||
track_caller = ($(#[$track_caller:tt])?),
|
track_caller = ($(#[$track_caller:tt])?),
|
||||||
which_module = |$self:ident| $which_module:expr,
|
which_module = |$self:ident, $global_io:ident| $which_module:expr,
|
||||||
) => {
|
) => {
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn read_bool_or_int<I: BoolOrIntType>(&mut $self, io: Expr<I>) -> I::Value {
|
pub $($async)? fn read_bool_or_int<I: BoolOrIntType>(&mut $self, io: Expr<I>) -> I::Value {
|
||||||
let retval = $self
|
let retval = $self.sim_impl.borrow_mut().read_bool_or_int(
|
||||||
.sim_impl
|
io,
|
||||||
.borrow_mut()
|
ReadTime::Current,
|
||||||
.read_bool_or_int(io, ReadTime::Current, $which_module);
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
$self.settle_if_needed(retval)$(.$await)?
|
$self.settle_if_needed(retval)$(.$await)?
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
|
|
@ -3464,64 +3872,74 @@ macro_rules! impl_simulation_methods {
|
||||||
$self.sim_impl.borrow_mut().write_bool_or_int(
|
$self.sim_impl.borrow_mut().write_bool_or_int(
|
||||||
io,
|
io,
|
||||||
SimValue::into_value(value),
|
SimValue::into_value(value),
|
||||||
$which_module,
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn write_clock(&mut $self, io: Expr<Clock>, value: bool) {
|
pub $($async)? fn write_clock(&mut $self, io: Expr<Clock>, value: bool) {
|
||||||
$self.sim_impl
|
$self.sim_impl.borrow_mut().write_bit(
|
||||||
.borrow_mut()
|
Expr::canonical(io),
|
||||||
.write_bit(Expr::canonical(io), value, $which_module);
|
value,
|
||||||
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn read_clock(&mut $self, io: Expr<Clock>) -> bool {
|
pub $($async)? fn read_clock(&mut $self, io: Expr<Clock>) -> bool {
|
||||||
let retval = $self
|
let retval = $self.sim_impl.borrow_mut().read_bit(
|
||||||
.sim_impl
|
Expr::canonical(io),
|
||||||
.borrow_mut()
|
ReadTime::Current,
|
||||||
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
$self.settle_if_needed(retval)$(.$await)?
|
$self.settle_if_needed(retval)$(.$await)?
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn write_bool(&mut $self, io: Expr<Bool>, value: bool) {
|
pub $($async)? fn write_bool(&mut $self, io: Expr<Bool>, value: bool) {
|
||||||
$self.sim_impl
|
$self.sim_impl.borrow_mut().write_bit(
|
||||||
.borrow_mut()
|
Expr::canonical(io),
|
||||||
.write_bit(Expr::canonical(io), value, $which_module);
|
value,
|
||||||
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn read_bool(&mut $self, io: Expr<Bool>) -> bool {
|
pub $($async)? fn read_bool(&mut $self, io: Expr<Bool>) -> bool {
|
||||||
let retval = $self
|
let retval = $self.sim_impl.borrow_mut().read_bit(
|
||||||
.sim_impl
|
Expr::canonical(io),
|
||||||
.borrow_mut()
|
ReadTime::Current,
|
||||||
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
$self.settle_if_needed(retval)$(.$await)?
|
$self.settle_if_needed(retval)$(.$await)?
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn write_reset<R: ResetType>(&mut $self, io: Expr<R>, value: bool) {
|
pub $($async)? fn write_reset<R: ResetType>(&mut $self, io: Expr<R>, value: bool) {
|
||||||
$self.sim_impl
|
$self.sim_impl.borrow_mut().write_bit(
|
||||||
.borrow_mut()
|
Expr::canonical(io),
|
||||||
.write_bit(Expr::canonical(io), value, $which_module);
|
value,
|
||||||
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn read_reset<R: ResetType>(&mut $self, io: Expr<R>) -> bool {
|
pub $($async)? fn read_reset<R: ResetType>(&mut $self, io: Expr<R>) -> bool {
|
||||||
let retval = $self
|
let retval = $self.sim_impl.borrow_mut().read_bit(
|
||||||
.sim_impl
|
Expr::canonical(io),
|
||||||
.borrow_mut()
|
ReadTime::Current,
|
||||||
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
);
|
||||||
$self.settle_if_needed(retval)$(.$await)?
|
$self.settle_if_needed(retval)$(.$await)?
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn is_reset_async<R: ResetType>(&$self, io: Expr<R>) -> bool {
|
pub fn is_reset_async<R: ResetType>(&$self, io: Expr<R>) -> bool {
|
||||||
$self
|
$self.sim_impl.borrow().is_reset_async(
|
||||||
.sim_impl
|
Expr::canonical(io),
|
||||||
.borrow_mut()
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
.is_reset_async(Expr::canonical(io), $which_module)
|
)
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
pub $($async)? fn read<IO: Type>(&mut $self, io: Expr<IO>) -> SimValue<IO> {
|
pub $($async)? fn read<IO: Type>(&mut $self, io: Expr<IO>) -> SimValue<IO> {
|
||||||
let retval = $self
|
let retval = $self.sim_impl.borrow_mut().read(
|
||||||
.sim_impl
|
Expr::canonical(io),
|
||||||
.borrow_mut()
|
ReadTime::Current,
|
||||||
.read(Expr::canonical(io), ReadTime::Current, $which_module).1;
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
|
).1;
|
||||||
SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?)
|
SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?)
|
||||||
}
|
}
|
||||||
$(#[$track_caller])?
|
$(#[$track_caller])?
|
||||||
|
|
@ -3529,7 +3947,7 @@ macro_rules! impl_simulation_methods {
|
||||||
$self.sim_impl.borrow_mut().write(
|
$self.sim_impl.borrow_mut().write(
|
||||||
Expr::canonical(io),
|
Expr::canonical(io),
|
||||||
&SimValue::into_canonical(value.into_sim_value_with_type(io.ty())),
|
&SimValue::into_canonical(value.into_sim_value_with_type(io.ty())),
|
||||||
$which_module,
|
|$global_io: &SimulationGlobalIo| $which_module,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -3568,6 +3986,9 @@ impl<T: BundleType> Simulation<T> {
|
||||||
pub fn io(&self) -> Expr<T> {
|
pub fn io(&self) -> Expr<T> {
|
||||||
self.io.to_expr()
|
self.io.to_expr()
|
||||||
}
|
}
|
||||||
|
pub fn global_io(&self) -> SimulationGlobalIo {
|
||||||
|
self.sim_impl.borrow().global_io.clone()
|
||||||
|
}
|
||||||
pub fn from_compiled(compiled: Compiled<T>) -> Self {
|
pub fn from_compiled(compiled: Compiled<T>) -> Self {
|
||||||
let sim_impl = SimulationImpl::new(compiled.canonical());
|
let sim_impl = SimulationImpl::new(compiled.canonical());
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -3593,7 +4014,7 @@ impl<T: BundleType> Simulation<T> {
|
||||||
impl_simulation_methods!(
|
impl_simulation_methods!(
|
||||||
async_await = (),
|
async_await = (),
|
||||||
track_caller = (#[track_caller]),
|
track_caller = (#[track_caller]),
|
||||||
which_module = |self| WhichModule::Main,
|
which_module = |self, global_io| WhichModule::Main { global_io },
|
||||||
);
|
);
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// This is explicitly unstable and may be changed/removed at any time
|
/// This is explicitly unstable and may be changed/removed at any time
|
||||||
|
|
@ -3662,7 +4083,7 @@ impl ExternModuleSimulationState {
|
||||||
let (key, value) = self
|
let (key, value) = self
|
||||||
.sim_impl
|
.sim_impl
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.read(io, ReadTime::Current, which_module);
|
.read(io, ReadTime::Current, |_| which_module);
|
||||||
let value = self.settle_if_needed(value).await;
|
let value = self.settle_if_needed(value).await;
|
||||||
let key = Rc::new(key);
|
let key = Rc::new(key);
|
||||||
if sensitivity_set.compiled_values.insert(key.clone()) {
|
if sensitivity_set.compiled_values.insert(key.clone()) {
|
||||||
|
|
@ -3934,7 +4355,7 @@ impl ExternModuleSimulationState {
|
||||||
let retval = self.sim_impl.borrow_mut().read_bool_or_int(
|
let retval = self.sim_impl.borrow_mut().read_bool_or_int(
|
||||||
io,
|
io,
|
||||||
ReadTime::Past { clock_for_past },
|
ReadTime::Past { clock_for_past },
|
||||||
WhichModule::Extern {
|
|_| WhichModule::Extern {
|
||||||
module_index: self.module_index,
|
module_index: self.module_index,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -3950,7 +4371,7 @@ impl ExternModuleSimulationState {
|
||||||
let retval = self.sim_impl.borrow_mut().read_bit(
|
let retval = self.sim_impl.borrow_mut().read_bit(
|
||||||
Expr::canonical(io),
|
Expr::canonical(io),
|
||||||
ReadTime::Past { clock_for_past },
|
ReadTime::Past { clock_for_past },
|
||||||
WhichModule::Extern {
|
|_| WhichModule::Extern {
|
||||||
module_index: self.module_index,
|
module_index: self.module_index,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -3966,7 +4387,7 @@ impl ExternModuleSimulationState {
|
||||||
let retval = self.sim_impl.borrow_mut().read_bit(
|
let retval = self.sim_impl.borrow_mut().read_bit(
|
||||||
Expr::canonical(io),
|
Expr::canonical(io),
|
||||||
ReadTime::Past { clock_for_past },
|
ReadTime::Past { clock_for_past },
|
||||||
WhichModule::Extern {
|
|_| WhichModule::Extern {
|
||||||
module_index: self.module_index,
|
module_index: self.module_index,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -3986,7 +4407,7 @@ impl ExternModuleSimulationState {
|
||||||
let retval = self.sim_impl.borrow_mut().read_bit(
|
let retval = self.sim_impl.borrow_mut().read_bit(
|
||||||
Expr::canonical(io),
|
Expr::canonical(io),
|
||||||
ReadTime::Past { clock_for_past },
|
ReadTime::Past { clock_for_past },
|
||||||
WhichModule::Extern {
|
|_| WhichModule::Extern {
|
||||||
module_index: self.module_index,
|
module_index: self.module_index,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -4009,7 +4430,7 @@ impl ExternModuleSimulationState {
|
||||||
.read(
|
.read(
|
||||||
Expr::canonical(io),
|
Expr::canonical(io),
|
||||||
ReadTime::Past { clock_for_past },
|
ReadTime::Past { clock_for_past },
|
||||||
WhichModule::Extern {
|
|_| WhichModule::Extern {
|
||||||
module_index: self.module_index,
|
module_index: self.module_index,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -4019,7 +4440,7 @@ impl ExternModuleSimulationState {
|
||||||
impl_simulation_methods!(
|
impl_simulation_methods!(
|
||||||
async_await = (async, await),
|
async_await = (async, await),
|
||||||
track_caller = (),
|
track_caller = (),
|
||||||
which_module = |self| WhichModule::Extern { module_index: self.module_index },
|
which_module = |self, _global_io| WhichModule::Extern { module_index: self.module_index },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -980,6 +980,7 @@ macro_rules! make_state {
|
||||||
pub(crate) insns: Interned<Insns<InsnsBuildingDone>>,
|
pub(crate) insns: Interned<Insns<InsnsBuildingDone>>,
|
||||||
pub(crate) pc: usize,
|
pub(crate) pc: usize,
|
||||||
pub(crate) memory_write_log: Vec<(StatePartIndex<StatePartKindMemories>, 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) $state_plural_field: StatePart<$state_kind>,)*
|
||||||
$(pub(crate) $type_plural_field: StatePart<$type_kind>,)*
|
$(pub(crate) $type_plural_field: StatePart<$type_kind>,)*
|
||||||
}
|
}
|
||||||
|
|
@ -990,6 +991,7 @@ macro_rules! make_state {
|
||||||
insns: _,
|
insns: _,
|
||||||
pc,
|
pc,
|
||||||
memory_write_log,
|
memory_write_log,
|
||||||
|
assert_failed_log,
|
||||||
$($state_plural_field,)*
|
$($state_plural_field,)*
|
||||||
$($type_plural_field,)*
|
$($type_plural_field,)*
|
||||||
} = self;
|
} = self;
|
||||||
|
|
@ -997,6 +999,7 @@ macro_rules! make_state {
|
||||||
.field("insns", &InsnsOfState(self))
|
.field("insns", &InsnsOfState(self))
|
||||||
.field("pc", pc)
|
.field("pc", pc)
|
||||||
.field("memory_write_log", memory_write_log)
|
.field("memory_write_log", memory_write_log)
|
||||||
|
.field("assert_failed_log", assert_failed_log)
|
||||||
$(.field(stringify!($state_plural_field), $state_plural_field))*
|
$(.field(stringify!($state_plural_field), $state_plural_field))*
|
||||||
$(.field(stringify!($type_plural_field), $type_plural_field))*
|
$(.field(stringify!($type_plural_field), $type_plural_field))*
|
||||||
.finish()
|
.finish()
|
||||||
|
|
@ -1009,6 +1012,7 @@ macro_rules! make_state {
|
||||||
insns,
|
insns,
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: Vec::with_capacity(32),
|
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),)*
|
$($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),)*
|
$($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)*
|
||||||
}
|
}
|
||||||
|
|
@ -1020,6 +1024,7 @@ macro_rules! make_state {
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
orig_pc: &mut self.pc,
|
orig_pc: &mut self.pc,
|
||||||
memory_write_log: &mut self.memory_write_log,
|
memory_write_log: &mut self.memory_write_log,
|
||||||
|
assert_failed_log: &mut self.assert_failed_log,
|
||||||
$($state_plural_field: self.$state_plural_field.borrow(),)*
|
$($state_plural_field: self.$state_plural_field.borrow(),)*
|
||||||
$($type_plural_field: self.$type_plural_field.borrow(),)*
|
$($type_plural_field: self.$type_plural_field.borrow(),)*
|
||||||
}
|
}
|
||||||
|
|
@ -1042,6 +1047,7 @@ macro_rules! make_state {
|
||||||
pub(crate) orig_pc: &'a mut usize,
|
pub(crate) orig_pc: &'a mut usize,
|
||||||
pub(crate) pc: usize,
|
pub(crate) pc: usize,
|
||||||
pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex<StatePartKindMemories>, 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) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)*
|
||||||
$(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)*
|
$(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)*
|
||||||
}
|
}
|
||||||
|
|
@ -1299,6 +1305,7 @@ impl State {
|
||||||
insns: _,
|
insns: _,
|
||||||
pc,
|
pc,
|
||||||
memory_write_log: _,
|
memory_write_log: _,
|
||||||
|
assert_failed_log: _,
|
||||||
memories: _,
|
memories: _,
|
||||||
small_slots: _,
|
small_slots: _,
|
||||||
big_slots: _,
|
big_slots: _,
|
||||||
|
|
@ -1338,6 +1345,10 @@ impl BorrowedState<'_> {
|
||||||
self.memory_write_log.push(log_entry);
|
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> {
|
fn bigint_pow2(width: usize) -> Interned<BigInt> {
|
||||||
|
|
@ -2105,6 +2116,19 @@ impl_insns! {
|
||||||
state.log_memory_write(memory, addr);
|
state.log_memory_write(memory, addr);
|
||||||
next!();
|
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 => {
|
Return => {
|
||||||
break RunResult::Return(());
|
break RunResult::Return(());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1508,6 +1508,8 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -1527,6 +1529,8 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
||||||
for SimOnly<L>
|
for SimOnly<L>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ use crate::{
|
||||||
prelude::PhantomConst,
|
prelude::PhantomConst,
|
||||||
sim::{
|
sim::{
|
||||||
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
|
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
|
||||||
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
|
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceFormalInput,
|
||||||
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
|
TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation,
|
||||||
TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, TraceScalarId,
|
TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar,
|
||||||
TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, TraceWire,
|
TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt,
|
||||||
TraceWriter, TraceWriterDecls,
|
TraceWire, TraceWriter, TraceWriterDecls,
|
||||||
time::{SimDuration, SimInstant},
|
time::{SimDuration, SimInstant},
|
||||||
value::DynSimOnlyValue,
|
value::DynSimOnlyValue,
|
||||||
},
|
},
|
||||||
|
|
@ -766,6 +766,7 @@ impl WriteTrace for TraceScope {
|
||||||
Self::Wire(v) => v.write_trace(writer, arg),
|
Self::Wire(v) => v.write_trace(writer, arg),
|
||||||
Self::Reg(v) => v.write_trace(writer, arg),
|
Self::Reg(v) => v.write_trace(writer, arg),
|
||||||
Self::ModuleIO(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::Bundle(v) => v.write_trace(writer, arg),
|
||||||
Self::Array(v) => v.write_trace(writer, arg),
|
Self::Array(v) => v.write_trace(writer, arg),
|
||||||
Self::EnumWithFields(v) => v.write_trace(writer, arg),
|
Self::EnumWithFields(v) => v.write_trace(writer, arg),
|
||||||
|
|
@ -963,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 {
|
impl WriteTrace for TraceBundle {
|
||||||
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
|
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
|
||||||
let ArgInType {
|
let ArgInType {
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ use crate::{
|
||||||
bundle::BundleType,
|
bundle::BundleType,
|
||||||
firrtl::ExportOptions,
|
firrtl::ExportOptions,
|
||||||
module::Module,
|
module::Module,
|
||||||
util::HashMap,
|
sim::{Simulation, vcd::VcdWriterDecls},
|
||||||
|
util::{HashMap, RcWriter},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
|
panic::Location,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
sync::{Mutex, OnceLock},
|
sync::{Mutex, OnceLock},
|
||||||
|
|
@ -222,3 +224,190 @@ pub fn assert_formal<M: AsRef<Module<T>>, T: BundleType>(
|
||||||
)
|
)
|
||||||
.expect("testing::assert_formal() failed");
|
.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;
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,39 @@ impl CanonicalType {
|
||||||
}
|
}
|
||||||
MyMemoize.get_owned((self, other))
|
MyMemoize.get_owned((self, other))
|
||||||
}
|
}
|
||||||
|
pub fn contains_sim_only(self) -> bool {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct MyMemoize;
|
||||||
|
impl Memoize for MyMemoize {
|
||||||
|
type Input = CanonicalType;
|
||||||
|
type InputOwned = CanonicalType;
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||||
|
match input {
|
||||||
|
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
CanonicalType::Array(ty) => ty.element().contains_sim_only(),
|
||||||
|
CanonicalType::Enum(ty) => ty
|
||||||
|
.variants()
|
||||||
|
.iter()
|
||||||
|
.any(|v| v.ty.is_some_and(CanonicalType::contains_sim_only)),
|
||||||
|
CanonicalType::Bundle(ty) => {
|
||||||
|
ty.fields().iter().any(|v| v.ty.contains_sim_only())
|
||||||
|
}
|
||||||
|
CanonicalType::AsyncReset(_)
|
||||||
|
| CanonicalType::SyncReset(_)
|
||||||
|
| CanonicalType::Reset(_)
|
||||||
|
| CanonicalType::Clock(_)
|
||||||
|
| CanonicalType::PhantomConst(_) => false,
|
||||||
|
CanonicalType::DynSimOnly(_) => true,
|
||||||
|
CanonicalType::TraceAsString(ty) => ty.inner_ty().contains_sim_only(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyMemoize.get_owned(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MatchVariantAndInactiveScope: Sized {
|
pub trait MatchVariantAndInactiveScope: Sized {
|
||||||
|
|
@ -1309,16 +1342,49 @@ trait TraceAsStringTrait: fmt::Debug + 'static + Send + Sync + SupportsPtrEqWith
|
||||||
fn can_substitute_type(&self, new_type: CanonicalType) -> bool;
|
fn can_substitute_type(&self, new_type: CanonicalType) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> TraceAsStringTrait for T {
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct TraceAsStringState<T: Type> {
|
||||||
|
ty: Interned<T>,
|
||||||
|
canonical_ty: CanonicalType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> TraceAsStringState<T> {
|
||||||
|
fn new(ty: Interned<T>) -> Interned<Self> {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct MyMemoize<T: Type>(PhantomData<T>);
|
||||||
|
impl<T: Type> Memoize for MyMemoize<T> {
|
||||||
|
type Input = Interned<T>;
|
||||||
|
type InputOwned = Interned<T>;
|
||||||
|
type Output = Interned<TraceAsStringState<T>>;
|
||||||
|
|
||||||
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||||
|
TraceAsStringState {
|
||||||
|
ty: *input,
|
||||||
|
canonical_ty: input.canonical(),
|
||||||
|
}
|
||||||
|
.intern_sized()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyMemoize(PhantomData).get_owned(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> fmt::Debug for TraceAsStringState<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.ty.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> TraceAsStringTrait for TraceAsStringState<T> {
|
||||||
fn trace_fmt(
|
fn trace_fmt(
|
||||||
&self,
|
&self,
|
||||||
opaque: OpaqueSimValueSlice<'_>,
|
opaque: OpaqueSimValueSlice<'_>,
|
||||||
f: &mut fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
fmt::Debug::fmt(&Type::sim_value_from_opaque(self, opaque), f)
|
fmt::Debug::fmt(&Type::sim_value_from_opaque(&*self.ty, opaque), f)
|
||||||
}
|
}
|
||||||
fn can_substitute_type(&self, new_type: CanonicalType) -> bool {
|
fn can_substitute_type(&self, new_type: CanonicalType) -> bool {
|
||||||
self.canonical().is_layout_equivalent(new_type)
|
self.canonical_ty.is_layout_equivalent(new_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1374,7 +1440,7 @@ impl<T: Type> TraceAsString<T> {
|
||||||
Self {
|
Self {
|
||||||
inner_ty: LazyInterned::Interned(inner_ty),
|
inner_ty: LazyInterned::Interned(inner_ty),
|
||||||
trace_as_string: LazyInterned::Interned(Interned::cast_unchecked(
|
trace_as_string: LazyInterned::Interned(Interned::cast_unchecked(
|
||||||
inner_ty,
|
TraceAsStringState::new(inner_ty),
|
||||||
|v| -> &dyn TraceAsStringTrait { v },
|
|v| -> &dyn TraceAsStringTrait { v },
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
@ -1548,7 +1614,10 @@ impl<T: StaticType> Default for TraceAsStringStaticTypeHelper<T> {
|
||||||
|
|
||||||
impl<T: StaticType> From<TraceAsStringStaticTypeHelper<T>> for Interned<dyn TraceAsStringTrait> {
|
impl<T: StaticType> From<TraceAsStringStaticTypeHelper<T>> for Interned<dyn TraceAsStringTrait> {
|
||||||
fn from(_value: TraceAsStringStaticTypeHelper<T>) -> Self {
|
fn from(_value: TraceAsStringStaticTypeHelper<T>) -> Self {
|
||||||
Interned::cast_unchecked(T::TYPE.intern_sized(), |v| -> &dyn TraceAsStringTrait { v })
|
Interned::cast_unchecked(
|
||||||
|
TraceAsStringState::new(T::TYPE.intern_sized()),
|
||||||
|
|v| -> &dyn TraceAsStringTrait { v },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1846,6 +1915,8 @@ fn trace_as_string_cow_into_inner_value<T: Type>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = <T as HdlPartialEqImpl<U>>::TRY_STRUCTURAL_EQ;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher;
|
||||||
#[cfg(not(feature = "unstable-test-hasher"))]
|
#[cfg(not(feature = "unstable-test-hasher"))]
|
||||||
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
|
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
|
||||||
|
|
||||||
pub(crate) type HashMap<K, V> = hashbrown::HashMap<K, V, DefaultBuildHasher>;
|
pub(crate) type HashMap<K, V, H = DefaultBuildHasher> = hashbrown::HashMap<K, V, H>;
|
||||||
pub(crate) type HashSet<T> = hashbrown::HashSet<T, DefaultBuildHasher>;
|
pub(crate) type HashSet<T, H = DefaultBuildHasher> = hashbrown::HashSet<T, H>;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
|
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
|
||||||
|
|
@ -43,7 +43,11 @@ pub use misc::{
|
||||||
};
|
};
|
||||||
pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice};
|
pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice};
|
||||||
|
|
||||||
|
pub mod bool_fixed_point_solver;
|
||||||
|
pub(crate) mod indented_print;
|
||||||
pub mod job_server;
|
pub mod job_server;
|
||||||
|
pub mod map_trait;
|
||||||
pub mod prefix_sum;
|
pub mod prefix_sum;
|
||||||
pub mod ready_valid;
|
pub mod ready_valid;
|
||||||
pub(crate) mod serde_by_id;
|
pub(crate) mod serde_by_id;
|
||||||
|
pub mod union_find_map;
|
||||||
|
|
|
||||||
711
crates/fayalite/src/util/bool_fixed_point_solver.rs
Normal file
711
crates/fayalite/src/util/bool_fixed_point_solver.rs
Normal file
|
|
@ -0,0 +1,711 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use petgraph::unionfind::UnionFind;
|
||||||
|
use std::{collections::BTreeSet, fmt};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Variable(usize);
|
||||||
|
|
||||||
|
impl Variable {
|
||||||
|
pub fn index(self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Variable {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Variable {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "v{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum Constraint {
|
||||||
|
/// `variable` is constrained to be [`!solver.unconstrained_variables_value()`](BoolFixedPointSolver::unconstrained_variables_value())
|
||||||
|
MaximallyConstrained { variable: Variable },
|
||||||
|
/// the constraint is `dest == src`
|
||||||
|
Equal { dest: Variable, src: Variable },
|
||||||
|
/// the constraint is `dest == dest & src`
|
||||||
|
And { dest: Variable, src: Variable },
|
||||||
|
/// the constraint is `dest == dest | src`
|
||||||
|
Or { dest: Variable, src: Variable },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
/// the constraint is `dest == dest & src`
|
||||||
|
struct AndConstraint {
|
||||||
|
dest: Variable,
|
||||||
|
src: Variable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AndConstraint {
|
||||||
|
fn from_or_constraint(or_constraint_dest: Variable, or_constraint_src: Variable) -> Self {
|
||||||
|
// `a == a | b` is equivalent to `b == b & a`
|
||||||
|
Self {
|
||||||
|
dest: or_constraint_src,
|
||||||
|
src: or_constraint_dest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for AndConstraint {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self { dest, src } = *self;
|
||||||
|
write!(f, "{dest} == {dest} & {src}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BoolFixedPointSolver {
|
||||||
|
variables_union_find: UnionFind<usize>,
|
||||||
|
variables_value: Vec<bool>,
|
||||||
|
maximally_constrained: Vec<bool>,
|
||||||
|
unconstrained_variables_value: bool,
|
||||||
|
solved: bool,
|
||||||
|
and_constraints: BTreeSet<AndConstraint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for BoolFixedPointSolver {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
variables_union_find,
|
||||||
|
variables_value,
|
||||||
|
maximally_constrained,
|
||||||
|
unconstrained_variables_value,
|
||||||
|
solved,
|
||||||
|
and_constraints,
|
||||||
|
} = self;
|
||||||
|
f.debug_struct("BoolFixedPointSolver")
|
||||||
|
.field(
|
||||||
|
"variables_union_find",
|
||||||
|
&fmt::from_fn(|f| {
|
||||||
|
f.debug_map()
|
||||||
|
.entries(
|
||||||
|
(0..variables_union_find.len())
|
||||||
|
.map(|i| (Variable(i), Variable(variables_union_find.find(i)))),
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"variables_value",
|
||||||
|
&fmt::from_fn(|f| {
|
||||||
|
let mut debug_map = f.debug_map();
|
||||||
|
for (i, v) in variables_value.iter().enumerate() {
|
||||||
|
if variables_union_find.find(i) == i {
|
||||||
|
debug_map.entry(&Variable(i), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_map.finish()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"maximally_constrained",
|
||||||
|
&fmt::from_fn(|f| {
|
||||||
|
let mut debug_map = f.debug_map();
|
||||||
|
for (i, v) in maximally_constrained.iter().enumerate() {
|
||||||
|
if variables_union_find.find(i) == i {
|
||||||
|
debug_map.entry(&Variable(i), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_map.finish()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"unconstrained_variables_value",
|
||||||
|
unconstrained_variables_value,
|
||||||
|
)
|
||||||
|
.field("solved", solved)
|
||||||
|
.field("and_constraints", and_constraints)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoolFixedPointSolver {
|
||||||
|
pub const fn new(unconstrained_variables_value: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
variables_union_find: UnionFind::new_empty(),
|
||||||
|
variables_value: Vec::new(),
|
||||||
|
maximally_constrained: Vec::new(),
|
||||||
|
unconstrained_variables_value,
|
||||||
|
solved: false,
|
||||||
|
and_constraints: BTreeSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unconstrained_variables_value(&self) -> bool {
|
||||||
|
self.unconstrained_variables_value
|
||||||
|
}
|
||||||
|
pub fn new_variable(&mut self) -> Variable {
|
||||||
|
let index = self.variables_union_find.new_set();
|
||||||
|
self.variables_value
|
||||||
|
.push(self.unconstrained_variables_value);
|
||||||
|
self.maximally_constrained.push(false);
|
||||||
|
self.solved = false;
|
||||||
|
Variable(index)
|
||||||
|
}
|
||||||
|
pub fn variable_count(&self) -> usize {
|
||||||
|
self.variables_union_find.len()
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn assert_variable_in_range(&self, variable: Variable) {
|
||||||
|
if variable.0 >= self.variable_count() {
|
||||||
|
panic!("invalid variable {variable:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn add_constraint(&mut self, constraint: Constraint) {
|
||||||
|
self.solved = false;
|
||||||
|
match constraint {
|
||||||
|
Constraint::MaximallyConstrained { variable } => {
|
||||||
|
self.assert_variable_in_range(variable);
|
||||||
|
self.maximally_constrained[self.variables_union_find.find_mut(variable.0)] = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Constraint::Equal { dest, src } => {
|
||||||
|
self.assert_variable_in_range(dest);
|
||||||
|
self.assert_variable_in_range(src);
|
||||||
|
let maximally_constrained = self.maximally_constrained
|
||||||
|
[self.variables_union_find.find_mut(dest.0)]
|
||||||
|
| self.maximally_constrained[self.variables_union_find.find_mut(src.0)];
|
||||||
|
self.variables_union_find.union(dest.0, src.0);
|
||||||
|
let merged_index = self.variables_union_find.find_mut(dest.0);
|
||||||
|
self.maximally_constrained[merged_index] = maximally_constrained;
|
||||||
|
}
|
||||||
|
Constraint::And { dest, src } => {
|
||||||
|
self.assert_variable_in_range(src);
|
||||||
|
self.assert_variable_in_range(dest);
|
||||||
|
if src != dest {
|
||||||
|
self.and_constraints.insert(AndConstraint { dest, src });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constraint::Or { dest, src } => {
|
||||||
|
self.assert_variable_in_range(src);
|
||||||
|
self.assert_variable_in_range(dest);
|
||||||
|
if src != dest {
|
||||||
|
self.and_constraints
|
||||||
|
.insert(AndConstraint::from_or_constraint(dest, src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn solve(&mut self) {
|
||||||
|
for (value, maximally_constrained) in self
|
||||||
|
.variables_value
|
||||||
|
.iter_mut()
|
||||||
|
.zip(&self.maximally_constrained)
|
||||||
|
{
|
||||||
|
*value = self.unconstrained_variables_value ^ *maximally_constrained;
|
||||||
|
}
|
||||||
|
let mut variables_to_constraints_map: Vec<Vec<AndConstraint>> =
|
||||||
|
vec![Vec::new(); self.variable_count()];
|
||||||
|
for &AndConstraint { mut dest, mut src } in &self.and_constraints {
|
||||||
|
dest.0 = self.variables_union_find.find_mut(dest.0);
|
||||||
|
src.0 = self.variables_union_find.find_mut(src.0);
|
||||||
|
if dest == src {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let constraint = AndConstraint { dest, src };
|
||||||
|
variables_to_constraints_map[dest.0].push(constraint);
|
||||||
|
variables_to_constraints_map[src.0].push(constraint);
|
||||||
|
}
|
||||||
|
let mut worklist: Vec<Variable> = (0..self.variable_count())
|
||||||
|
.filter(|&index| self.variables_union_find.find_mut(index) == index)
|
||||||
|
.map(Variable)
|
||||||
|
.collect();
|
||||||
|
while let Some(variable) = worklist.pop() {
|
||||||
|
for &AndConstraint { dest, src } in &variables_to_constraints_map[variable.0] {
|
||||||
|
let dest_value = self.variables_value[dest.0];
|
||||||
|
let src_value = self.variables_value[src.0];
|
||||||
|
// equivalent to `dest_value != dest_value & src_value`:
|
||||||
|
let is_unsatisfied = dest_value && !src_value;
|
||||||
|
if is_unsatisfied {
|
||||||
|
if self.unconstrained_variables_value {
|
||||||
|
self.variables_value[dest.0] = false;
|
||||||
|
worklist.push(dest);
|
||||||
|
} else {
|
||||||
|
self.variables_value[src.0] = true;
|
||||||
|
worklist.push(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.solved = true;
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn value(&mut self, variable: Variable) -> bool {
|
||||||
|
#[cold]
|
||||||
|
fn solve_cold(this: &mut BoolFixedPointSolver) {
|
||||||
|
this.solve();
|
||||||
|
}
|
||||||
|
self.assert_variable_in_range(variable);
|
||||||
|
if !self.solved {
|
||||||
|
solve_cold(self);
|
||||||
|
}
|
||||||
|
self.variables_value[self.variables_union_find.find_mut(variable.0)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::num::NonZero;
|
||||||
|
|
||||||
|
struct TestCase<'a, C, Vars, Vals> {
|
||||||
|
variable_count: usize,
|
||||||
|
expected_values: Option<&'a [bool]>,
|
||||||
|
constraints: C,
|
||||||
|
variables: Vars,
|
||||||
|
values: Vals,
|
||||||
|
solver: BoolFixedPointSolver,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C: FnOnce(&[Variable]) -> I, I: IntoIterator<Item = Constraint>> TestCase<'a, C, (), ()> {
|
||||||
|
fn new_expected(
|
||||||
|
unconstrained_variables_value: bool,
|
||||||
|
expected_values: &'a [bool],
|
||||||
|
constraints: C,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
variable_count: expected_values.len(),
|
||||||
|
expected_values: Some(expected_values),
|
||||||
|
constraints,
|
||||||
|
variables: (),
|
||||||
|
values: (),
|
||||||
|
solver: BoolFixedPointSolver::new(unconstrained_variables_value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn get_constraints_and_variables(
|
||||||
|
self,
|
||||||
|
) -> TestCase<'a, Vec<Constraint>, Vec<Variable>, [bool; 0]> {
|
||||||
|
let Self {
|
||||||
|
variable_count,
|
||||||
|
expected_values,
|
||||||
|
constraints,
|
||||||
|
variables: (),
|
||||||
|
values: (),
|
||||||
|
mut solver,
|
||||||
|
} = self;
|
||||||
|
assert_eq!(
|
||||||
|
expected_values.map_or(variable_count, |v| v.len()),
|
||||||
|
variable_count,
|
||||||
|
);
|
||||||
|
let variables = Vec::from_iter((0..variable_count).map(|_| solver.new_variable()));
|
||||||
|
let constraints = Vec::from_iter(constraints(&variables));
|
||||||
|
TestCase {
|
||||||
|
variable_count,
|
||||||
|
expected_values,
|
||||||
|
constraints,
|
||||||
|
variables,
|
||||||
|
values: [],
|
||||||
|
solver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TestCase<'a, Vec<Constraint>, Vec<Variable>, [bool; 0]> {
|
||||||
|
#[track_caller]
|
||||||
|
fn add_and_check_constraints(&mut self) {
|
||||||
|
if let Some(expected_values) = self.expected_values {
|
||||||
|
self.check_constraints("expected values", expected_values);
|
||||||
|
}
|
||||||
|
for &constraint in &self.constraints {
|
||||||
|
self.solver.add_constraint(constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn get_values(self) -> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vec<bool>> {
|
||||||
|
let Self {
|
||||||
|
variable_count,
|
||||||
|
expected_values,
|
||||||
|
constraints,
|
||||||
|
variables,
|
||||||
|
values: [],
|
||||||
|
mut solver,
|
||||||
|
} = self;
|
||||||
|
let values = Vec::from_iter(variables.iter().map(|&v| solver.value(v)));
|
||||||
|
TestCase {
|
||||||
|
variable_count,
|
||||||
|
expected_values,
|
||||||
|
constraints,
|
||||||
|
variables,
|
||||||
|
values,
|
||||||
|
solver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vec<bool>> {
|
||||||
|
#[track_caller]
|
||||||
|
fn check_values(&self) {
|
||||||
|
let Self {
|
||||||
|
variable_count: _,
|
||||||
|
expected_values,
|
||||||
|
constraints: _,
|
||||||
|
variables,
|
||||||
|
values,
|
||||||
|
solver: _,
|
||||||
|
} = self;
|
||||||
|
if let Some(expected_values) = expected_values {
|
||||||
|
for ((&expected_value, &variable), &value) in
|
||||||
|
expected_values.iter().zip(variables).zip(values)
|
||||||
|
{
|
||||||
|
if expected_value != value {
|
||||||
|
self.error(format_args!(
|
||||||
|
"solver output for {variable} of {value:?} doesn't \
|
||||||
|
match expected value of {expected_value:?}",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.check_constraints("solved values", values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Vals: AsRef<[bool]>> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vals> {
|
||||||
|
#[track_caller]
|
||||||
|
fn check_constraints(&self, values_name: &str, values: &[bool]) {
|
||||||
|
let unconstrained_variables_value = self.solver.unconstrained_variables_value();
|
||||||
|
let v = |variable: Variable| values[variable.index()];
|
||||||
|
for &constraint in &self.constraints {
|
||||||
|
let satisfied = match constraint {
|
||||||
|
Constraint::MaximallyConstrained { variable } => {
|
||||||
|
v(variable) != unconstrained_variables_value
|
||||||
|
}
|
||||||
|
Constraint::Equal { dest, src } => v(dest) == v(src),
|
||||||
|
Constraint::And { dest, src } => v(dest) == v(dest) & v(src),
|
||||||
|
Constraint::Or { dest, src } => v(dest) == v(dest) | v(src),
|
||||||
|
};
|
||||||
|
if !satisfied {
|
||||||
|
self.error(format_args!(
|
||||||
|
"{values_name} don't satisfy constraint: {constraint:#?}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn error(&self, msg: fmt::Arguments<'_>) -> ! {
|
||||||
|
let Self {
|
||||||
|
variable_count,
|
||||||
|
expected_values,
|
||||||
|
ref constraints,
|
||||||
|
ref variables,
|
||||||
|
ref values,
|
||||||
|
ref solver,
|
||||||
|
} = *self;
|
||||||
|
let values = values.as_ref();
|
||||||
|
panic!(
|
||||||
|
"{msg}\n\
|
||||||
|
values={values:#?}\n\
|
||||||
|
constraints={constraints:#?}\n\
|
||||||
|
solver={solver:#?}",
|
||||||
|
values = fmt::from_fn(|f| {
|
||||||
|
let mut debug_map = f.debug_map();
|
||||||
|
for i in 0..variable_count {
|
||||||
|
debug_map.key(&variables[i]);
|
||||||
|
if let Some(value) = values.get(i) {
|
||||||
|
if let Some(expected_values) = expected_values {
|
||||||
|
debug_map.value(&format_args!(
|
||||||
|
"{value:?} (expected: {:?})",
|
||||||
|
expected_values[i],
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
debug_map.value(value);
|
||||||
|
}
|
||||||
|
} else if let Some(expected_values) = expected_values {
|
||||||
|
debug_map.value(&format_args!("(expected: {:?})", expected_values[i]));
|
||||||
|
} else {
|
||||||
|
debug_map.value(&format_args!("None"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_map.finish()
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn test_case<I: IntoIterator<Item = Constraint>>(
|
||||||
|
test_case: TestCase<'_, impl FnOnce(&[Variable]) -> I, (), ()>,
|
||||||
|
) {
|
||||||
|
let mut test_case = test_case.get_constraints_and_variables();
|
||||||
|
test_case.add_and_check_constraints();
|
||||||
|
let test_case = test_case.get_values();
|
||||||
|
test_case.check_values();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_simple() {
|
||||||
|
test_case(TestCase::new_expected(false, &[], |_| []));
|
||||||
|
test_case(TestCase::new_expected(true, &[], |_| []));
|
||||||
|
test_case(TestCase::new_expected(false, &[false], |_| []));
|
||||||
|
test_case(TestCase::new_expected(true, &[true], |_| []));
|
||||||
|
test_case(TestCase::new_expected(false, &[true], |v| {
|
||||||
|
[Constraint::MaximallyConstrained { variable: v[0] }]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false], |v| {
|
||||||
|
[Constraint::MaximallyConstrained { variable: v[0] }]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(false, &[true, true], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Equal {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false, false], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Equal {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(false, &[true, false], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::And {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false, false], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::And {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(false, &[true, true], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::And {
|
||||||
|
dest: v[0],
|
||||||
|
src: v[1],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false, true], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::And {
|
||||||
|
dest: v[0],
|
||||||
|
src: v[1],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(false, &[true, true], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Or {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false, true], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Or {
|
||||||
|
dest: v[1],
|
||||||
|
src: v[0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(false, &[true, false], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Or {
|
||||||
|
dest: v[0],
|
||||||
|
src: v[1],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
test_case(TestCase::new_expected(true, &[false, false], |v| {
|
||||||
|
[
|
||||||
|
Constraint::MaximallyConstrained { variable: v[0] },
|
||||||
|
Constraint::Or {
|
||||||
|
dest: v[0],
|
||||||
|
src: v[1],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Rng {
|
||||||
|
state: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rng {
|
||||||
|
fn new(test_case_index: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
state: (test_case_index as u64) << 32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
self.state += 1;
|
||||||
|
// 4 random primes and 4 random rotate amounts
|
||||||
|
self.state
|
||||||
|
.wrapping_mul(0xA3C7_8807_EA6D_A4F9)
|
||||||
|
.rotate_left(43)
|
||||||
|
.wrapping_mul(0x1CCA_797A_6BF8_8C63)
|
||||||
|
.rotate_left(8)
|
||||||
|
.wrapping_mul(0xCC50_AA59_7C41_946F)
|
||||||
|
.rotate_left(12)
|
||||||
|
.wrapping_mul(0xFB2A_0137_F878_C4B5)
|
||||||
|
.rotate_left(58)
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn next_u64_in_range(&mut self, range: std::ops::Range<u64>) -> u64 {
|
||||||
|
let Some(len) = range.end.checked_sub(range.start).and_then(NonZero::new) else {
|
||||||
|
panic!("empty range: {range:?}");
|
||||||
|
};
|
||||||
|
let max_quotient = u64::MAX / len;
|
||||||
|
loop {
|
||||||
|
let next_u64 = self.next_u64();
|
||||||
|
let quotient = next_u64 / len;
|
||||||
|
let remainder = next_u64 % len;
|
||||||
|
if quotient < max_quotient {
|
||||||
|
return remainder + range.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn next_usize_in_range(&mut self, range: std::ops::Range<usize>) -> usize {
|
||||||
|
self.next_u64_in_range(range.start as u64..range.end as u64) as usize
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn next_from_slice<'a, T>(&mut self, slice: &'a [T]) -> &'a T {
|
||||||
|
assert!(!slice.is_empty());
|
||||||
|
&slice[self.next_usize_in_range(0..slice.len())]
|
||||||
|
}
|
||||||
|
fn next_bool(&mut self) -> bool {
|
||||||
|
(self.next_u64() & 1) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn test_bool_fixed_point_solver_random_case(test_case_index: u32) {
|
||||||
|
println!("test_bool_fixed_point_solver_random_case({test_case_index})");
|
||||||
|
let mut rng = Rng::new(test_case_index);
|
||||||
|
// bias towards smaller problems to make them easier to debug
|
||||||
|
let variable_count = rng
|
||||||
|
.next_u64_in_range(1..1_000_000)
|
||||||
|
.pow(2)
|
||||||
|
.div_ceil(1_000_000_000) as usize;
|
||||||
|
let constraint_count =
|
||||||
|
rng.next_usize_in_range(0..(variable_count * variable_count).clamp(0, 10000));
|
||||||
|
let solver = BoolFixedPointSolver::new(rng.next_bool());
|
||||||
|
test_case(TestCase {
|
||||||
|
variable_count,
|
||||||
|
expected_values: None,
|
||||||
|
constraints: |variables: &[Variable]| {
|
||||||
|
Vec::from_iter(
|
||||||
|
(0..constraint_count).map(|_| match rng.next_usize_in_range(0..4) {
|
||||||
|
0 => Constraint::MaximallyConstrained {
|
||||||
|
variable: *rng.next_from_slice(variables),
|
||||||
|
},
|
||||||
|
1 => Constraint::Equal {
|
||||||
|
dest: *rng.next_from_slice(variables),
|
||||||
|
src: *rng.next_from_slice(variables),
|
||||||
|
},
|
||||||
|
2 => Constraint::And {
|
||||||
|
dest: *rng.next_from_slice(variables),
|
||||||
|
src: *rng.next_from_slice(variables),
|
||||||
|
},
|
||||||
|
3 => Constraint::Or {
|
||||||
|
dest: *rng.next_from_slice(variables),
|
||||||
|
src: *rng.next_from_slice(variables),
|
||||||
|
},
|
||||||
|
4.. => unreachable!(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
variables: (),
|
||||||
|
values: (),
|
||||||
|
solver,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const CASES_FULL_RANGE: std::ops::Range<u32> = 0..100_000;
|
||||||
|
|
||||||
|
fn mul_div(v: u32, factor: u32, divisor: u32) -> u32 {
|
||||||
|
((v as u64 * factor as u64) / divisor as u64) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases(split_index: u32) {
|
||||||
|
assert!(split_index < CASES_SPLIT_COUNT);
|
||||||
|
let full_range_len = CASES_FULL_RANGE.end - CASES_FULL_RANGE.start;
|
||||||
|
let start = mul_div(split_index, full_range_len, CASES_SPLIT_COUNT);
|
||||||
|
let end = mul_div(split_index + 1, full_range_len, CASES_SPLIT_COUNT);
|
||||||
|
for test_case_index in start..end {
|
||||||
|
test_bool_fixed_point_solver_random_case(test_case_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CASES_SPLIT_COUNT: u32 = 10;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_0() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_1() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_2() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_3() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_4() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_5() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_6() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_7() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_8() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bool_fixed_point_solver_random_cases_9() {
|
||||||
|
test_bool_fixed_point_solver_random_cases(9);
|
||||||
|
}
|
||||||
|
}
|
||||||
117
crates/fayalite/src/util/indented_print.rs
Normal file
117
crates/fayalite/src/util/indented_print.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Write as _},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndentState {
|
||||||
|
indent: usize,
|
||||||
|
need_indent: bool,
|
||||||
|
buf: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static INDENT_STATE: std::cell::RefCell<IndentState> = const {
|
||||||
|
std::cell::RefCell::new(IndentState {
|
||||||
|
indent: 0,
|
||||||
|
need_indent: true,
|
||||||
|
buf: String::new(),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IndentedOut;
|
||||||
|
|
||||||
|
impl fmt::Write for IndentedOut {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
INDENT_STATE.with_borrow_mut(|state| {
|
||||||
|
let IndentState {
|
||||||
|
indent,
|
||||||
|
need_indent,
|
||||||
|
buf,
|
||||||
|
} = state;
|
||||||
|
buf.clear();
|
||||||
|
for ch in s.chars() {
|
||||||
|
if ch == '\n' {
|
||||||
|
*need_indent = true;
|
||||||
|
} else {
|
||||||
|
if *need_indent {
|
||||||
|
*need_indent = false;
|
||||||
|
for _ in 0..*indent {
|
||||||
|
buf.push_str(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.push(ch)
|
||||||
|
}
|
||||||
|
std::print!("{buf}");
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) struct PushIndent(PhantomData<*const ()>);
|
||||||
|
|
||||||
|
impl Drop for PushIndent {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = INDENT_STATE.try_with(|state| state.borrow_mut().indent -= 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushIndent {
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
INDENT_STATE.with_borrow_mut(|state| state.indent += 1);
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) fn indented_print_fmt<const LN: bool>(args: fmt::Arguments<'_>) {
|
||||||
|
if LN {
|
||||||
|
writeln!(IndentedOut, "{args}").expect("writing can't fail")
|
||||||
|
} else {
|
||||||
|
IndentedOut.write_fmt(args).expect("writing can't fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
macro_rules! indented_print {
|
||||||
|
($($args:tt)*) => {
|
||||||
|
$crate::util::indented_print::indented_print_fmt::<false>($crate::__std::format_args!($($args)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) use indented_print;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
macro_rules! indented_println {
|
||||||
|
($($args:tt)*) => {
|
||||||
|
$crate::util::indented_print::indented_print_fmt::<true>($crate::__std::format_args!($($args)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) use indented_println;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
macro_rules! indented_dbg {
|
||||||
|
($expr:expr) => {{
|
||||||
|
let v = $expr;
|
||||||
|
$crate::util::indented_print::indented_println!(
|
||||||
|
"[{}:{}:{}] {} = {v:#?}",
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
stringify!($expr),
|
||||||
|
);
|
||||||
|
v
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) use indented_dbg;
|
||||||
463
crates/fayalite/src/util/map_trait.rs
Normal file
463
crates/fayalite/src/util/map_trait.rs
Normal file
|
|
@ -0,0 +1,463 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub enum Entry<'a, M: Map + 'a> {
|
||||||
|
Vacant(M::VacantEntry<'a>),
|
||||||
|
Occupied(M::OccupiedEntry<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: Map + 'a> Entry<'a, M> {
|
||||||
|
pub fn and_modify<F: FnOnce(&mut M::Value)>(mut self, f: F) -> Self {
|
||||||
|
if let Self::Occupied(entry) = &mut self {
|
||||||
|
f(entry.get_mut());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn insert_entry(self, v: M::Value) -> M::OccupiedEntry<'a> {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert_entry(v),
|
||||||
|
Self::Occupied(mut entry) => {
|
||||||
|
entry.insert(v);
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn key(&self) -> &M::Key {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.key(),
|
||||||
|
Self::Occupied(entry) => entry.key(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn or_default(self) -> &'a mut M::Value
|
||||||
|
where
|
||||||
|
M::Value: Default,
|
||||||
|
{
|
||||||
|
self.or_insert_with(Default::default)
|
||||||
|
}
|
||||||
|
pub fn or_insert(self, v: M::Value) -> &'a mut M::Value {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert(v),
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn or_insert_with<F: FnOnce() -> M::Value>(self, f: F) -> &'a mut M::Value {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert(f()),
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn or_insert_with_key<F: FnOnce(&M::Key) -> M::Value>(self, f: F) -> &'a mut M::Value {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => {
|
||||||
|
let v = f(entry.key());
|
||||||
|
entry.insert(v)
|
||||||
|
}
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: Map<OccupiedEntry<'a>: fmt::Debug, VacantEntry<'a>: fmt::Debug> + 'a> fmt::Debug
|
||||||
|
for Entry<'a, M>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(v) => f.debug_tuple("Vacant").field(v).finish(),
|
||||||
|
Self::Occupied(v) => f.debug_tuple("Occupied").field(v).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait VacantEntry<'a>: Sized {
|
||||||
|
type Map: Map<VacantEntry<'a> = Self> + 'a;
|
||||||
|
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value;
|
||||||
|
fn insert_entry(self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::OccupiedEntry<'a>;
|
||||||
|
fn into_key(self) -> <Self::Map as Map>::Key;
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OccupiedEntry<'a>: Sized {
|
||||||
|
type Map: Map<OccupiedEntry<'a> = Self> + 'a;
|
||||||
|
fn get(&self) -> &<Self::Map as Map>::Value;
|
||||||
|
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value;
|
||||||
|
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value;
|
||||||
|
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value;
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key;
|
||||||
|
fn remove(self) -> <Self::Map as Map>::Value;
|
||||||
|
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Map:
|
||||||
|
Sized
|
||||||
|
+ IntoIterator<Item = (<Self as Map>::Key, <Self as Map>::Value)>
|
||||||
|
+ Extend<(<Self as Map>::Key, <Self as Map>::Value)>
|
||||||
|
+ FromIterator<(<Self as Map>::Key, <Self as Map>::Value)>
|
||||||
|
{
|
||||||
|
type Key;
|
||||||
|
type Value;
|
||||||
|
type IntoKeys: Iterator<Item = Self::Key>;
|
||||||
|
type IntoValues: Iterator<Item = Self::Value>;
|
||||||
|
type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type IterMut<'a>: Iterator<Item = (&'a Self::Key, &'a mut Self::Value)>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type Keys<'a>: Iterator<Item = &'a Self::Key>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a;
|
||||||
|
type Values<'a>: Iterator<Item = &'a Self::Value>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type ValuesMut<'a>: Iterator<Item = &'a mut Self::Value>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type OccupiedEntry<'a>: OccupiedEntry<'a, Map = Self>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
type VacantEntry<'a>: VacantEntry<'a, Map = Self>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn clear(&mut self);
|
||||||
|
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self>;
|
||||||
|
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value>;
|
||||||
|
fn into_keys(self) -> Self::IntoKeys;
|
||||||
|
fn into_values(self) -> Self::IntoValues;
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
fn iter(&self) -> Self::Iter<'_>;
|
||||||
|
fn iter_mut(&mut self) -> Self::IterMut<'_>;
|
||||||
|
fn keys(&self) -> Self::Keys<'_>;
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F);
|
||||||
|
fn values(&self) -> Self::Values<'_>;
|
||||||
|
fn values_mut(&mut self) -> Self::ValuesMut<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MapGet<Q: ?Sized>: Map {
|
||||||
|
fn contains_key(&self, k: &Q) -> bool;
|
||||||
|
fn get(&self, k: &Q) -> Option<&Self::Value>;
|
||||||
|
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value>;
|
||||||
|
fn remove(&mut self, k: &Q) -> Option<Self::Value>;
|
||||||
|
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod hash_map {
|
||||||
|
use super::*;
|
||||||
|
use crate::util::HashMap;
|
||||||
|
use hashbrown::{Equivalent, hash_map};
|
||||||
|
use std::hash::{BuildHasher, Hash};
|
||||||
|
|
||||||
|
impl<K: Eq + Hash, V, H: BuildHasher + Default> Map for HashMap<K, V, H> {
|
||||||
|
type Key = K;
|
||||||
|
type Value = V;
|
||||||
|
type IntoKeys = hash_map::IntoKeys<K, V>;
|
||||||
|
type IntoValues = hash_map::IntoValues<K, V>;
|
||||||
|
type Iter<'a>
|
||||||
|
= hash_map::Iter<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type IterMut<'a>
|
||||||
|
= hash_map::IterMut<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type Keys<'a>
|
||||||
|
= hash_map::Keys<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a;
|
||||||
|
type Values<'a>
|
||||||
|
= hash_map::Values<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type ValuesMut<'a>
|
||||||
|
= hash_map::ValuesMut<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type OccupiedEntry<'a>
|
||||||
|
= hash_map::OccupiedEntry<'a, K, V, H>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
type VacantEntry<'a>
|
||||||
|
= hash_map::VacantEntry<'a, K, V, H>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> {
|
||||||
|
use hash_map::Entry::*;
|
||||||
|
match self.entry(k) {
|
||||||
|
Occupied(entry) => Entry::Occupied(entry),
|
||||||
|
Vacant(entry) => Entry::Vacant(entry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value> {
|
||||||
|
self.insert(k, v)
|
||||||
|
}
|
||||||
|
fn into_keys(self) -> Self::IntoKeys {
|
||||||
|
self.into_keys()
|
||||||
|
}
|
||||||
|
fn into_values(self) -> Self::IntoValues {
|
||||||
|
self.into_values()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.is_empty()
|
||||||
|
}
|
||||||
|
fn iter(&self) -> Self::Iter<'_> {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
fn iter_mut(&mut self) -> Self::IterMut<'_> {
|
||||||
|
self.iter_mut()
|
||||||
|
}
|
||||||
|
fn keys(&self) -> Self::Keys<'_> {
|
||||||
|
self.keys()
|
||||||
|
}
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F) {
|
||||||
|
self.retain(f);
|
||||||
|
}
|
||||||
|
fn values(&self) -> Self::Values<'_> {
|
||||||
|
self.values()
|
||||||
|
}
|
||||||
|
fn values_mut(&mut self) -> Self::ValuesMut<'_> {
|
||||||
|
self.values_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Eq + Hash, V, H: BuildHasher + Default, Q: ?Sized + Hash + Equivalent<K>> MapGet<Q>
|
||||||
|
for HashMap<K, V, H>
|
||||||
|
{
|
||||||
|
fn contains_key(&self, k: &Q) -> bool {
|
||||||
|
self.contains_key(k)
|
||||||
|
}
|
||||||
|
fn get(&self, k: &Q) -> Option<&Self::Value> {
|
||||||
|
self.get(k)
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> {
|
||||||
|
self.get_mut(k)
|
||||||
|
}
|
||||||
|
fn remove(&mut self, k: &Q) -> Option<Self::Value> {
|
||||||
|
self.remove(k)
|
||||||
|
}
|
||||||
|
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> {
|
||||||
|
self.remove_entry(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> VacantEntry<'a>
|
||||||
|
for hash_map::VacantEntry<'a, K, V, H>
|
||||||
|
{
|
||||||
|
type Map = HashMap<K, V, H>;
|
||||||
|
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
|
||||||
|
self.insert(v)
|
||||||
|
}
|
||||||
|
fn insert_entry(
|
||||||
|
self,
|
||||||
|
v: <Self::Map as Map>::Value,
|
||||||
|
) -> <Self::Map as Map>::OccupiedEntry<'a> {
|
||||||
|
self.insert_entry(v)
|
||||||
|
}
|
||||||
|
fn into_key(self) -> <Self::Map as Map>::Key {
|
||||||
|
self.into_key()
|
||||||
|
}
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key {
|
||||||
|
self.key()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> OccupiedEntry<'a>
|
||||||
|
for hash_map::OccupiedEntry<'a, K, V, H>
|
||||||
|
{
|
||||||
|
type Map = HashMap<K, V, H>;
|
||||||
|
fn get(&self) -> &<Self::Map as Map>::Value {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
|
||||||
|
self.get_mut()
|
||||||
|
}
|
||||||
|
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
|
||||||
|
self.insert(v)
|
||||||
|
}
|
||||||
|
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
|
||||||
|
self.into_mut()
|
||||||
|
}
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key {
|
||||||
|
self.key()
|
||||||
|
}
|
||||||
|
fn remove(self) -> <Self::Map as Map>::Value {
|
||||||
|
self.remove()
|
||||||
|
}
|
||||||
|
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
|
||||||
|
self.remove_entry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod btree_map {
|
||||||
|
use super::*;
|
||||||
|
use std::collections::{BTreeMap, btree_map};
|
||||||
|
|
||||||
|
impl<K: Ord, V> Map for BTreeMap<K, V> {
|
||||||
|
type Key = K;
|
||||||
|
type Value = V;
|
||||||
|
type IntoKeys = btree_map::IntoKeys<K, V>;
|
||||||
|
type IntoValues = btree_map::IntoValues<K, V>;
|
||||||
|
type Iter<'a>
|
||||||
|
= btree_map::Iter<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type IterMut<'a>
|
||||||
|
= btree_map::IterMut<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type Keys<'a>
|
||||||
|
= btree_map::Keys<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Key: 'a;
|
||||||
|
type Values<'a>
|
||||||
|
= btree_map::Values<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type ValuesMut<'a>
|
||||||
|
= btree_map::ValuesMut<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
Self::Value: 'a;
|
||||||
|
type OccupiedEntry<'a>
|
||||||
|
= btree_map::OccupiedEntry<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
type VacantEntry<'a>
|
||||||
|
= btree_map::VacantEntry<'a, K, V>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> {
|
||||||
|
use btree_map::Entry::*;
|
||||||
|
match self.entry(k) {
|
||||||
|
Occupied(entry) => Entry::Occupied(entry),
|
||||||
|
Vacant(entry) => Entry::Vacant(entry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value> {
|
||||||
|
self.insert(k, v)
|
||||||
|
}
|
||||||
|
fn into_keys(self) -> Self::IntoKeys {
|
||||||
|
self.into_keys()
|
||||||
|
}
|
||||||
|
fn into_values(self) -> Self::IntoValues {
|
||||||
|
self.into_values()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.is_empty()
|
||||||
|
}
|
||||||
|
fn iter(&self) -> Self::Iter<'_> {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
fn iter_mut(&mut self) -> Self::IterMut<'_> {
|
||||||
|
self.iter_mut()
|
||||||
|
}
|
||||||
|
fn keys(&self) -> Self::Keys<'_> {
|
||||||
|
self.keys()
|
||||||
|
}
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F) {
|
||||||
|
self.retain(f);
|
||||||
|
}
|
||||||
|
fn values(&self) -> Self::Values<'_> {
|
||||||
|
self.values()
|
||||||
|
}
|
||||||
|
fn values_mut(&mut self) -> Self::ValuesMut<'_> {
|
||||||
|
self.values_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ord + std::borrow::Borrow<Q>, V, Q: ?Sized + Ord> MapGet<Q> for BTreeMap<K, V> {
|
||||||
|
fn contains_key(&self, k: &Q) -> bool {
|
||||||
|
self.contains_key(k)
|
||||||
|
}
|
||||||
|
fn get(&self, k: &Q) -> Option<&Self::Value> {
|
||||||
|
self.get(k)
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> {
|
||||||
|
self.get_mut(k)
|
||||||
|
}
|
||||||
|
fn remove(&mut self, k: &Q) -> Option<Self::Value> {
|
||||||
|
self.remove(k)
|
||||||
|
}
|
||||||
|
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> {
|
||||||
|
self.remove_entry(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K: Ord, V> VacantEntry<'a> for btree_map::VacantEntry<'a, K, V> {
|
||||||
|
type Map = BTreeMap<K, V>;
|
||||||
|
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
|
||||||
|
self.insert(v)
|
||||||
|
}
|
||||||
|
fn insert_entry(
|
||||||
|
self,
|
||||||
|
v: <Self::Map as Map>::Value,
|
||||||
|
) -> <Self::Map as Map>::OccupiedEntry<'a> {
|
||||||
|
self.insert_entry(v)
|
||||||
|
}
|
||||||
|
fn into_key(self) -> <Self::Map as Map>::Key {
|
||||||
|
self.into_key()
|
||||||
|
}
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key {
|
||||||
|
self.key()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K: Ord, V> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> {
|
||||||
|
type Map = BTreeMap<K, V>;
|
||||||
|
fn get(&self) -> &<Self::Map as Map>::Value {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
|
||||||
|
self.get_mut()
|
||||||
|
}
|
||||||
|
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
|
||||||
|
self.insert(v)
|
||||||
|
}
|
||||||
|
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
|
||||||
|
self.into_mut()
|
||||||
|
}
|
||||||
|
fn key(&self) -> &<Self::Map as Map>::Key {
|
||||||
|
self.key()
|
||||||
|
}
|
||||||
|
fn remove(self) -> <Self::Map as Map>::Value {
|
||||||
|
self.remove()
|
||||||
|
}
|
||||||
|
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
|
||||||
|
self.remove_entry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -241,15 +241,13 @@ mod tests {
|
||||||
/// happens to be in phase with the offending input or output).
|
/// happens to be in phase with the offending input or output).
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
|
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
|
||||||
#[hdl]
|
|
||||||
let clk: Clock = m.input();
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd = wire();
|
let cd = wire();
|
||||||
connect(
|
connect(
|
||||||
cd,
|
cd,
|
||||||
#[hdl]
|
#[hdl]
|
||||||
ClockDomain {
|
ClockDomain {
|
||||||
clk,
|
clk: formal_global_clock(),
|
||||||
rst: formal_reset().to_reset(),
|
rst: formal_reset().to_reset(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -280,7 +278,7 @@ mod tests {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let index_to_check = wire(index_ty);
|
let index_to_check = wire(index_ty);
|
||||||
connect(index_to_check, any_const(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
|
// instantiate and connect the queue
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -300,13 +298,13 @@ mod tests {
|
||||||
let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero());
|
let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) {
|
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);
|
connect_any(expected_count_reg, expected_count_reg + 1u8);
|
||||||
} else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) {
|
} 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);
|
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
|
// keep an independent write index into the FIFO's circular buffer
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -374,7 +372,7 @@ mod tests {
|
||||||
match inp_firing_data {
|
match inp_firing_data {
|
||||||
// ... and we are not receiving data, then we must not
|
// ... and we are not receiving data, then we must not
|
||||||
// transmit any data.
|
// 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...
|
// If we are indeed receiving some data...
|
||||||
HdlSome(data_in) => {
|
HdlSome(data_in) => {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -382,7 +380,9 @@ mod tests {
|
||||||
// ... and transmitting at the same time, we
|
// ... and transmitting at the same time, we
|
||||||
// must be transmitting the input data itself,
|
// must be transmitting the input data itself,
|
||||||
// since the holding register is empty.
|
// 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,
|
// If we are receiving, but not transmitting,
|
||||||
// store the received data in the holding
|
// store the received data in the holding
|
||||||
// register.
|
// register.
|
||||||
|
|
@ -397,11 +397,11 @@ mod tests {
|
||||||
match out_firing_data {
|
match out_firing_data {
|
||||||
// ... and we are not transmitting it, we cannot
|
// ... and we are not transmitting it, we cannot
|
||||||
// receive any more data.
|
// 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...
|
// If we are transmitting a previously stored value...
|
||||||
HdlSome(data_out) => {
|
HdlSome(data_out) => {
|
||||||
// ... it must be the same data we stored earlier.
|
// ... 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,
|
// Also, accept new data, if any. Otherwise,
|
||||||
// let the holding register become empty.
|
// let the holding register become empty.
|
||||||
connect(stored_reg, inp_firing_data);
|
connect(stored_reg, inp_firing_data);
|
||||||
|
|
@ -417,17 +417,17 @@ mod tests {
|
||||||
connect(dut.dbg.index_to_check, index_to_check);
|
connect(dut.dbg.index_to_check, index_to_check);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(stored) = stored_reg {
|
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
|
// sync the read and write indices
|
||||||
hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
|
hdl_assert(cd.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, out_index_reg.cmp_eq(dut.dbg.out_index), "");
|
||||||
|
|
||||||
// the indices should never go past the capacity, but induction
|
// the indices should never go past the capacity, but induction
|
||||||
// doesn't know that...
|
// doesn't know that...
|
||||||
hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), "");
|
hdl_assert(cd.clk, inp_index_reg.cmp_lt(capacity.get()), "");
|
||||||
hdl_assert(clk, out_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
|
// strongly constrain the state of the holding register
|
||||||
//
|
//
|
||||||
|
|
@ -455,7 +455,7 @@ mod tests {
|
||||||
connect(expected_stored, pending_reads.cmp_lt(dut.count));
|
connect(expected_stored, pending_reads.cmp_lt(dut.count));
|
||||||
// sync with the state of the holding register
|
// sync with the state of the holding register
|
||||||
hdl_assert(
|
hdl_assert(
|
||||||
clk,
|
cd.clk,
|
||||||
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
|
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
|
||||||
352
crates/fayalite/src/util/union_find_map.rs
Normal file
352
crates/fayalite/src/util/union_find_map.rs
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::util::{
|
||||||
|
HashMap,
|
||||||
|
map_trait::{self, Map, MapGet, OccupiedEntry as _, VacantEntry as _},
|
||||||
|
};
|
||||||
|
use petgraph::unionfind::UnionFind;
|
||||||
|
use std::{collections::BTreeMap, fmt, marker::PhantomData};
|
||||||
|
|
||||||
|
pub struct UnionFindMap<K, V, M = HashMap<K, usize>> {
|
||||||
|
uf: UnionFind<usize>,
|
||||||
|
keys_to_indexes: M,
|
||||||
|
values: Vec<Option<V>>,
|
||||||
|
_phantom: PhantomData<K>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: fmt::Debug, V: fmt::Debug, M: Map<Key = K, Value = usize>> fmt::Debug
|
||||||
|
for UnionFindMap<K, V, M>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut indexes_to_keys = vec![None; self.len()];
|
||||||
|
for (k, &index) in self.keys_to_indexes.iter() {
|
||||||
|
indexes_to_keys[index] = Some(k);
|
||||||
|
}
|
||||||
|
let mut debug_map = f.debug_map();
|
||||||
|
for (index, key) in indexes_to_keys.into_iter().enumerate() {
|
||||||
|
if let Some(key) = key {
|
||||||
|
debug_map.key(key);
|
||||||
|
} else {
|
||||||
|
debug_map.key(&fmt::from_fn(|f| {
|
||||||
|
f.write_str("<<there's a misbehaving key>>")
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
let set_index = self.uf.find(index);
|
||||||
|
debug_map.value(&fmt::from_fn(|f| {
|
||||||
|
write!(f, "@{set_index} ")?;
|
||||||
|
if set_index == index {
|
||||||
|
let Some(value) = &self.values[index] else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
value.fmt(f)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
debug_map.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V, M: Map<Key = K, Value = usize>> UnionFindMap<K, V, M> {
|
||||||
|
/// returns the number of keys, not the number of sets/values
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.values.len()
|
||||||
|
}
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
pub fn capacity(&self) -> usize {
|
||||||
|
self.values.capacity()
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn equiv<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> bool
|
||||||
|
where
|
||||||
|
M: MapGet<K1> + MapGet<K2>,
|
||||||
|
{
|
||||||
|
self.try_equiv(k1, k2).expect("key not found")
|
||||||
|
}
|
||||||
|
pub fn try_equiv<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> Option<bool>
|
||||||
|
where
|
||||||
|
M: MapGet<K1> + MapGet<K2>,
|
||||||
|
{
|
||||||
|
let &index1 = self.keys_to_indexes.get(k1)?;
|
||||||
|
let &index2 = self.keys_to_indexes.get(k2)?;
|
||||||
|
Some(self.uf.equiv(index1, index2))
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn find<Q: ?Sized>(&self, k: &Q) -> &V
|
||||||
|
where
|
||||||
|
M: MapGet<Q>,
|
||||||
|
{
|
||||||
|
self.try_find(k).expect("key not found")
|
||||||
|
}
|
||||||
|
pub fn try_find<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||||
|
where
|
||||||
|
M: MapGet<Q>,
|
||||||
|
{
|
||||||
|
let &index = self.keys_to_indexes.get(k)?;
|
||||||
|
self.values[self.uf.find(index)].as_ref()
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn find_mut<Q: ?Sized>(&mut self, k: &Q) -> &mut V
|
||||||
|
where
|
||||||
|
M: MapGet<Q>,
|
||||||
|
{
|
||||||
|
self.try_find_mut(k).expect("key not found")
|
||||||
|
}
|
||||||
|
pub fn try_find_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||||
|
where
|
||||||
|
M: MapGet<Q>,
|
||||||
|
{
|
||||||
|
let &index = self.keys_to_indexes.get(k)?;
|
||||||
|
self.values[self.uf.find_mut(index)].as_mut()
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key
|
||||||
|
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
|
||||||
|
match self.entry(k) {
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(v);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Entry::Occupied(mut entry) => Some(entry.insert(v)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn entry(&mut self, k: K) -> Entry<'_, K, V, M> {
|
||||||
|
match self.keys_to_indexes.entry(k) {
|
||||||
|
map_trait::Entry::Vacant(keys_to_indexes_entry) => Entry::Vacant(VacantEntry {
|
||||||
|
keys_to_indexes_entry,
|
||||||
|
uf: &mut self.uf,
|
||||||
|
values: &mut self.values,
|
||||||
|
}),
|
||||||
|
map_trait::Entry::Occupied(keys_to_indexes_entry) => {
|
||||||
|
let set_index = self.uf.find_mut(*keys_to_indexes_entry.get());
|
||||||
|
Entry::Occupied(OccupiedEntry {
|
||||||
|
keys_to_indexes_entry,
|
||||||
|
set_index,
|
||||||
|
values: &mut self.values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Unify the two sets containing `k1` and `k2`.
|
||||||
|
/// If the sets were the same, returns `Some((false, value))`,
|
||||||
|
/// otherwise calling `merge` to merge their values and returning `Some((true, value))`.
|
||||||
|
/// Returns `None` if either of the keys weren't found.
|
||||||
|
pub fn try_union<K1: ?Sized, K2: ?Sized, F>(
|
||||||
|
&mut self,
|
||||||
|
k1: &K1,
|
||||||
|
k2: &K2,
|
||||||
|
merge: F,
|
||||||
|
) -> Option<(bool, &mut V)>
|
||||||
|
where
|
||||||
|
M: MapGet<K1> + MapGet<K2>,
|
||||||
|
F: FnOnce(&K1, V, &K2, V) -> V,
|
||||||
|
{
|
||||||
|
let &index1 = self.keys_to_indexes.get(k1)?;
|
||||||
|
let &index2 = self.keys_to_indexes.get(k2)?;
|
||||||
|
let index1 = self.uf.find_mut(index1);
|
||||||
|
let index2 = self.uf.find_mut(index2);
|
||||||
|
if index1 == index2 {
|
||||||
|
return Some((false, self.values[index1].as_mut()?));
|
||||||
|
}
|
||||||
|
assert!(self.uf.union(index1, index2));
|
||||||
|
let v1 = self.values[index1].take().expect("known to be Some");
|
||||||
|
let v2 = self.values[index2].take().expect("known to be Some");
|
||||||
|
let dest = &mut self.values[self.uf.find_mut(index1)];
|
||||||
|
let dest = dest.insert(merge(k1, v1, k2, v2));
|
||||||
|
Some((true, dest))
|
||||||
|
}
|
||||||
|
/// Unify the two sets containing `k1` and `k2`.
|
||||||
|
/// If the sets were the same, returns `(false, value)`,
|
||||||
|
/// otherwise calling `merge` to merge their values and returning `(true, value)`.
|
||||||
|
/// panics if either of the keys weren't found.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn union<K1: ?Sized, K2: ?Sized, F>(&mut self, k1: &K1, k2: &K2, merge: F) -> (bool, &mut V)
|
||||||
|
where
|
||||||
|
M: MapGet<K1> + MapGet<K2>,
|
||||||
|
F: FnOnce(&K1, V, &K2, V) -> V,
|
||||||
|
{
|
||||||
|
self.try_union(k1, k2, merge).expect("key not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> UnionFindMap<K, V> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::with_hasher(Default::default())
|
||||||
|
}
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self::with_capacity_and_hasher(capacity, Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> UnionFindMap<K, V, BTreeMap<K, usize>> {
|
||||||
|
pub const fn new_btree() -> Self {
|
||||||
|
Self {
|
||||||
|
uf: UnionFind::new_empty(),
|
||||||
|
keys_to_indexes: BTreeMap::new(),
|
||||||
|
values: Vec::new(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V, H> UnionFindMap<K, V, HashMap<K, usize, H>> {
|
||||||
|
pub const fn with_hasher(hash_builder: H) -> Self {
|
||||||
|
Self {
|
||||||
|
uf: UnionFind::new_empty(),
|
||||||
|
keys_to_indexes: HashMap::with_hasher(hash_builder),
|
||||||
|
values: Vec::new(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: H) -> Self {
|
||||||
|
Self {
|
||||||
|
uf: UnionFind::with_capacity(capacity),
|
||||||
|
keys_to_indexes: HashMap::with_capacity_and_hasher(capacity, hash_builder),
|
||||||
|
values: Vec::with_capacity(capacity),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V, M: Default> Default for UnionFindMap<K, V, M> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
uf: UnionFind::new_empty(),
|
||||||
|
keys_to_indexes: M::default(),
|
||||||
|
values: Vec::new(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OccupiedEntry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
|
||||||
|
keys_to_indexes_entry: M::OccupiedEntry<'a>,
|
||||||
|
set_index: usize,
|
||||||
|
values: &'a mut [Option<V>],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> OccupiedEntry<'a, K, V, M> {
|
||||||
|
pub fn get(&self) -> &V {
|
||||||
|
let Some(v) = &self.values[self.set_index] else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
v
|
||||||
|
}
|
||||||
|
pub fn get_mut(&mut self) -> &mut V {
|
||||||
|
let Some(v) = &mut self.values[self.set_index] else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
v
|
||||||
|
}
|
||||||
|
/// replaces the value for this set
|
||||||
|
pub fn insert(&mut self, v: V) -> V {
|
||||||
|
std::mem::replace(self.get_mut(), v)
|
||||||
|
}
|
||||||
|
pub fn into_mut(self) -> &'a mut V {
|
||||||
|
let Some(v) = &mut self.values[self.set_index] else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
v
|
||||||
|
}
|
||||||
|
pub fn key(&self) -> &K {
|
||||||
|
self.keys_to_indexes_entry.key()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VacantEntry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
|
||||||
|
keys_to_indexes_entry: M::VacantEntry<'a>,
|
||||||
|
uf: &'a mut UnionFind<usize>,
|
||||||
|
values: &'a mut Vec<Option<V>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> VacantEntry<'a, K, V, M> {
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn insert(self, v: V) -> &'a mut V {
|
||||||
|
self.insert_entry(v).into_mut()
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> {
|
||||||
|
let Self {
|
||||||
|
keys_to_indexes_entry,
|
||||||
|
uf,
|
||||||
|
values,
|
||||||
|
} = self;
|
||||||
|
let set_index = uf.new_set();
|
||||||
|
values.push(Some(v));
|
||||||
|
OccupiedEntry {
|
||||||
|
keys_to_indexes_entry: keys_to_indexes_entry.insert_entry(set_index),
|
||||||
|
set_index,
|
||||||
|
values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_key(self) -> K {
|
||||||
|
self.keys_to_indexes_entry.into_key()
|
||||||
|
}
|
||||||
|
pub fn key(&self) -> &K {
|
||||||
|
self.keys_to_indexes_entry.key()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Entry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
|
||||||
|
Vacant(VacantEntry<'a, K, V, M>),
|
||||||
|
Occupied(OccupiedEntry<'a, K, V, M>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> Entry<'a, K, V, M> {
|
||||||
|
pub fn and_modify<F: FnOnce(&mut V)>(mut self, f: F) -> Self {
|
||||||
|
if let Self::Occupied(entry) = &mut self {
|
||||||
|
f(entry.get_mut());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key
|
||||||
|
pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert_entry(v),
|
||||||
|
Self::Occupied(mut entry) => {
|
||||||
|
entry.insert(v);
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn key(&self) -> &K {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.key(),
|
||||||
|
Self::Occupied(entry) => entry.key(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn or_default(self) -> &'a mut V
|
||||||
|
where
|
||||||
|
V: Default,
|
||||||
|
{
|
||||||
|
self.or_insert_with(V::default)
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn or_insert(self, v: V) -> &'a mut V {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert(v),
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn or_insert_with<F: FnOnce() -> V>(self, f: F) -> &'a mut V {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => entry.insert(f()),
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// inserts a new key as a new set
|
||||||
|
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, f: F) -> &'a mut V {
|
||||||
|
match self {
|
||||||
|
Self::Vacant(entry) => {
|
||||||
|
let v = f(entry.key());
|
||||||
|
entry.insert(v)
|
||||||
|
}
|
||||||
|
Self::Occupied(entry) => entry.into_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -595,6 +595,9 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
|
||||||
v,
|
v,
|
||||||
instance.source_location(),
|
instance.source_location(),
|
||||||
)? {},
|
)? {},
|
||||||
|
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
|
||||||
|
unreachable!("base.is_valid_annotation_target() is known to be false")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,13 @@ impl<T: Type> Wire<T> {
|
||||||
ty: T::from_canonical(ty),
|
ty: T::from_canonical(ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[track_caller]
|
||||||
pub fn new_unchecked(
|
pub fn new_unchecked(
|
||||||
scoped_name: ScopedNameId,
|
scoped_name: ScopedNameId,
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
ty: T,
|
ty: T,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
scoped_name.0.assert_is_name_id();
|
||||||
Self {
|
Self {
|
||||||
name: scoped_name,
|
name: scoped_name,
|
||||||
source_location,
|
source_location,
|
||||||
|
|
@ -76,7 +78,7 @@ impl<T: Type> Wire<T> {
|
||||||
self.containing_module_name_id().0
|
self.containing_module_name_id().0
|
||||||
}
|
}
|
||||||
pub fn containing_module_name_id(&self) -> NameId {
|
pub fn containing_module_name_id(&self) -> NameId {
|
||||||
self.name.0
|
self.name.0.unwrap_name_id()
|
||||||
}
|
}
|
||||||
pub fn name(&self) -> Interned<str> {
|
pub fn name(&self) -> Interned<str> {
|
||||||
self.name_id().0
|
self.name_id().0
|
||||||
|
|
|
||||||
4247
crates/fayalite/tests/deduce_structural_eq_flags.rs
Normal file
4247
crates/fayalite/tests/deduce_structural_eq_flags.rs
Normal file
File diff suppressed because it is too large
Load diff
6
crates/fayalite/tests/expected/my_test.md
Normal file
6
crates/fayalite/tests/expected/my_test.md
Normal 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`
|
||||||
13
crates/fayalite/tests/expected/my_test.vcd
Normal file
13
crates/fayalite/tests/expected/my_test.vcd
Normal 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/
|
||||||
|
|
@ -709,44 +709,35 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_enum_to_bits_expr: UInt<10>
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
match lhs:
|
||||||
match lhs: @[module-XXXXXXXXXX.rs 5:1]
|
|
||||||
A:
|
A:
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<10>(0)
|
||||||
A:
|
B(_cast_enum_to_bits_expr_B):
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
|
||||||
B(_match_arm_value):
|
C(_cast_enum_to_bits_expr_C):
|
||||||
skip
|
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||||
C(_match_arm_value_1):
|
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
|
||||||
skip
|
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
|
||||||
B(_match_arm_value_2):
|
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_to_bits_expr: UInt<3>
|
||||||
A:
|
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]))
|
||||||
skip
|
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
|
||||||
B(_match_arm_value_3):
|
wire _cast_enum_to_bits_expr_1: UInt<10>
|
||||||
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
|
match rhs:
|
||||||
C(_match_arm_value_4):
|
A:
|
||||||
skip
|
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
|
||||||
C(_match_arm_value_5):
|
B(_cast_enum_to_bits_expr_B_1):
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
|
||||||
A:
|
C(_cast_enum_to_bits_expr_C_1):
|
||||||
skip
|
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
||||||
B(_match_arm_value_6):
|
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
|
||||||
skip
|
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
|
||||||
C(_match_arm_value_7):
|
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_to_bits_expr_1: UInt<3>
|
||||||
connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
|
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 _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
|
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
|
||||||
connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2])
|
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[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 lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
match lhs.tag: @[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:
|
A:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(0)
|
||||||
A:
|
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
|
||||||
B:
|
|
||||||
skip
|
|
||||||
C:
|
|
||||||
skip
|
|
||||||
B:
|
B:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(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
|
|
||||||
C:
|
C:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(2)
|
||||||
A:
|
wire _cast_enum_to_bits_expr_1: UInt<2>
|
||||||
skip
|
match rhs.tag:
|
||||||
B:
|
A:
|
||||||
skip
|
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
|
||||||
C:
|
B:
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
C:
|
||||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
|
||||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
A:
|
||||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
B:
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
C:
|
||||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 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], _cast_bits_to_array_expr_flattened[1]
|
||||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
wire _cast_bits_to_array_expr_2: UInt<1>[3]
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: 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_flattened_1[0], bits(bits(rhs.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_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||||
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.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_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||||
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||||
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
wire _cast_bits_to_array_expr_3: UInt<1>[3]
|
wire _array_structural_eq: UInt<1>
|
||||||
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
|
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]))
|
||||||
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
wire _array_structural_eq_1: UInt<1>
|
||||||
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
|
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||||
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[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 lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
skip
|
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
else:
|
||||||
skip
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
else:
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened: 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_flattened[0], bits(bits(lhs.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[0], _cast_bits_to_array_expr_flattened[0]
|
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.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[1], _cast_bits_to_array_expr_flattened[1]
|
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
wire _array_structural_eq: UInt<1>
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
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 _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _array_structural_eq_1: UInt<1>
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[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 lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
skip
|
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5: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]
|
||||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
else:
|
||||||
skip
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
||||||
else:
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened: 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_flattened[0], bits(bits(bits(lhs, 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[0], _cast_bits_to_array_expr_flattened[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_flattened[1], bits(bits(bits(lhs, 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[1], _cast_bits_to_array_expr_flattened[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_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
wire _array_structural_eq: UInt<1>
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
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 _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _array_structural_eq_1: UInt<1>
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -3779,20 +3637,176 @@ circuit check_formal: %[[
|
||||||
input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
|
input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1]
|
input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1]
|
||||||
input pred3: UInt<1> @[module-XXXXXXXXXX.rs 8: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]
|
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.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1]
|
||||||
assume(clk, pred2, and(en2, not(formal_reset_1.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]
|
||||||
inst formal_reset_2 of formal_reset @[formal.rs 185:24]
|
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
|
||||||
cover(clk, pred3, and(en3, not(formal_reset_2.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1]
|
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
|
||||||
inst formal_reset_3 of formal_reset @[formal.rs 185:24]
|
cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1]
|
||||||
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset_3.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
|
extmodule formal_reset: @[builtin 1:1]
|
||||||
inst formal_reset_4 of formal_reset @[formal.rs 185:24]
|
output rst: UInt<1> @[builtin 1:1]
|
||||||
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset_4.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
|
defname = __fayalite_formal_reset
|
||||||
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]
|
|
||||||
|
#[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
|
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]
|
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
HdlSome:
|
HdlSome:
|
||||||
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
|
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:
|
; connect different types:
|
||||||
; lhs: SInt<1>
|
; lhs: SInt<1>
|
||||||
; rhs: SInt<2>
|
; 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
|
wire _bundle_literal_expr_2: Ty4
|
||||||
connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome)
|
connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome)
|
||||||
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
|
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]
|
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
C:
|
C:
|
||||||
wire __connect_variant_body_3: Ty8 @[module-XXXXXXXXXX.rs 8:1]
|
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_1: Ty8
|
||||||
wire _cast_bits_to_bundle_expr_flattened_2: Ty9
|
wire _cast_bits_to_bundle_expr_flattened_1: Ty9
|
||||||
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0)
|
||||||
wire _cast_bits_to_enum_expr_2: Ty3
|
wire _cast_bits_to_enum_expr_1: Ty3
|
||||||
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
|
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)):
|
||||||
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
|
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone)
|
||||||
else:
|
else:
|
||||||
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
|
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome)
|
||||||
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
|
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1
|
||||||
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
|
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
|
||||||
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
|
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_2 @[module-XXXXXXXXXX.rs 8:1]
|
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
wire _bundle_literal_expr_4: Ty1
|
wire _bundle_literal_expr_4: Ty1
|
||||||
connect _bundle_literal_expr_4.tag, {|A, B, C|}(C)
|
connect _bundle_literal_expr_4.tag, {|A, B, C|}(C)
|
||||||
wire _cast_bundle_to_bits_expr_1: Ty9
|
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]
|
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
B:
|
B:
|
||||||
wire __connect_variant_body_5: Ty5 @[module-XXXXXXXXXX.rs 9:1]
|
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_2: Ty4
|
||||||
wire _cast_bits_to_bundle_expr_flattened_3: Ty7
|
wire _cast_bits_to_bundle_expr_flattened_2: Ty7
|
||||||
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0)
|
||||||
wire _cast_bits_to_enum_expr_3: Ty3
|
wire _cast_bits_to_enum_expr_2: Ty3
|
||||||
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
|
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
|
||||||
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
|
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
|
||||||
else:
|
else:
|
||||||
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
|
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
|
||||||
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
|
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
|
||||||
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
|
connect _cast_bits_to_bundle_expr_flattened_2.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
|
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
|
||||||
match _cast_bits_to_bundle_expr_3.tag: @[module-XXXXXXXXXX.rs 9:1]
|
match _cast_bits_to_bundle_expr_2.tag: @[module-XXXXXXXXXX.rs 9:1]
|
||||||
HdlNone:
|
HdlNone:
|
||||||
wire _bundle_literal_expr_6: Ty5
|
wire _bundle_literal_expr_6: Ty5
|
||||||
connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone)
|
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]
|
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
HdlSome:
|
HdlSome:
|
||||||
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
|
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:
|
; connect different types:
|
||||||
; lhs: SInt<2>
|
; lhs: SInt<2>
|
||||||
; rhs: SInt<1>
|
; 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
|
wire _bundle_literal_expr_7: Ty5
|
||||||
connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome)
|
connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome)
|
||||||
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
|
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]
|
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
C:
|
C:
|
||||||
wire __connect_variant_body_7: Ty8 @[module-XXXXXXXXXX.rs 9:1]
|
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_3: Ty8
|
||||||
wire _cast_bits_to_bundle_expr_flattened_5: Ty9
|
wire _cast_bits_to_bundle_expr_flattened_3: Ty9
|
||||||
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0)
|
||||||
wire _cast_bits_to_enum_expr_5: Ty3
|
wire _cast_bits_to_enum_expr_3: Ty3
|
||||||
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)):
|
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
|
||||||
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone)
|
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
|
||||||
else:
|
else:
|
||||||
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome)
|
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
|
||||||
connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_5
|
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
|
||||||
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
|
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
|
||||||
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
|
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_5 @[module-XXXXXXXXXX.rs 9:1]
|
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
wire _bundle_literal_expr_9: Ty2
|
wire _bundle_literal_expr_9: Ty2
|
||||||
connect _bundle_literal_expr_9.tag, {|A, B, C|}(C)
|
connect _bundle_literal_expr_9.tag, {|A, B, C|}(C)
|
||||||
wire _cast_bundle_to_bits_expr_3: Ty9
|
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]
|
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
else:
|
else:
|
||||||
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
|
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:
|
; connect different types:
|
||||||
; lhs: SInt<1>
|
; lhs: SInt<1>
|
||||||
; rhs: SInt<2>
|
; 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
|
wire _bundle_literal_expr_2: Ty2
|
||||||
connect _bundle_literal_expr_2.tag, UInt<1>(0h1)
|
connect _bundle_literal_expr_2.tag, UInt<1>(0h1)
|
||||||
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
|
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]
|
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
else:
|
else:
|
||||||
wire __connect_variant_body_3: Ty4 @[module-XXXXXXXXXX.rs 8:1]
|
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_1: Ty4
|
||||||
wire _cast_bits_to_bundle_expr_flattened_2: Ty4
|
wire _cast_bits_to_bundle_expr_flattened_1: Ty4
|
||||||
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_1.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_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag
|
||||||
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
|
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
|
||||||
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
|
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_2 @[module-XXXXXXXXXX.rs 8:1]
|
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
wire _bundle_literal_expr_4: Ty0
|
wire _bundle_literal_expr_4: Ty0
|
||||||
connect _bundle_literal_expr_4.tag, UInt<2>(0h2)
|
connect _bundle_literal_expr_4.tag, UInt<2>(0h2)
|
||||||
wire _cast_bundle_to_bits_expr_1: Ty4
|
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]
|
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
else when eq(i1.tag, UInt<2>(0h1)): @[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 __connect_variant_body_5: Ty3 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
wire _cast_bits_to_bundle_expr_3: Ty2
|
wire _cast_bits_to_bundle_expr_2: Ty2
|
||||||
wire _cast_bits_to_bundle_expr_flattened_3: Ty2
|
wire _cast_bits_to_bundle_expr_flattened_2: Ty2
|
||||||
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_2.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_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag
|
||||||
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
|
connect _cast_bits_to_bundle_expr_flattened_2.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
|
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
|
||||||
when eq(_cast_bits_to_bundle_expr_3.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
|
when eq(_cast_bits_to_bundle_expr_2.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
|
||||||
wire _bundle_literal_expr_6: Ty3
|
wire _bundle_literal_expr_6: Ty3
|
||||||
connect _bundle_literal_expr_6.tag, UInt<1>(0h0)
|
connect _bundle_literal_expr_6.tag, UInt<1>(0h0)
|
||||||
connect _bundle_literal_expr_6.body, UInt<2>(0h0)
|
connect _bundle_literal_expr_6.body, UInt<2>(0h0)
|
||||||
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
|
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
else:
|
else:
|
||||||
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
|
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:
|
; connect different types:
|
||||||
; lhs: SInt<2>
|
; lhs: SInt<2>
|
||||||
; rhs: SInt<1>
|
; 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
|
wire _bundle_literal_expr_7: Ty3
|
||||||
connect _bundle_literal_expr_7.tag, UInt<1>(0h1)
|
connect _bundle_literal_expr_7.tag, UInt<1>(0h1)
|
||||||
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
|
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]
|
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
else:
|
else:
|
||||||
wire __connect_variant_body_7: Ty4 @[module-XXXXXXXXXX.rs 9:1]
|
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_3: Ty4
|
||||||
wire _cast_bits_to_bundle_expr_flattened_5: Ty4
|
wire _cast_bits_to_bundle_expr_flattened_3: Ty4
|
||||||
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
|
connect _cast_bits_to_bundle_expr_flattened_3.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_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag
|
||||||
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
|
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
|
||||||
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
|
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_5 @[module-XXXXXXXXXX.rs 9:1]
|
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
wire _bundle_literal_expr_9: Ty1
|
wire _bundle_literal_expr_9: Ty1
|
||||||
connect _bundle_literal_expr_9.tag, UInt<2>(0h2)
|
connect _bundle_literal_expr_9.tag, UInt<2>(0h2)
|
||||||
wire _cast_bundle_to_bits_expr_3: Ty4
|
wire _cast_bundle_to_bits_expr_3: Ty4
|
||||||
|
|
@ -4883,34 +4863,20 @@ circuit check_struct_cmp_eq:
|
||||||
input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1]
|
input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1]
|
||||||
output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1]
|
output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1]
|
||||||
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
|
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _bundle_structural_eq: UInt<1>
|
||||||
connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`)
|
connect _bundle_structural_eq, and(eq(tuple_lhs.`0`, tuple_rhs.`0`), eq(tuple_lhs.`1`, tuple_rhs.`1`))
|
||||||
connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`)
|
wire _bundle_structural_eq_1: UInt<1>
|
||||||
connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`)
|
connect _bundle_structural_eq_1, and(_bundle_structural_eq, eq(tuple_lhs.`2`, tuple_rhs.`2`))
|
||||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
connect tuple_cmp_eq, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
connect tuple_cmp_ne, not(_bundle_structural_eq_1) @[module-XXXXXXXXXX.rs 7:1]
|
||||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
wire _bundle_structural_eq_2: UInt<1>
|
||||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
connect _bundle_structural_eq_2, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b))
|
||||||
wire _cast_to_bits_expr: UInt<3>
|
connect test_struct_cmp_eq, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 11:1]
|
||||||
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 test_struct_cmp_ne, not(_bundle_structural_eq_2) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
connect tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
|
||||||
wire _array_literal_expr_1: UInt<1>[3]
|
|
||||||
connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`)
|
|
||||||
connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`)
|
|
||||||
connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`)
|
|
||||||
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
|
||||||
connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0]
|
|
||||||
connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1]
|
|
||||||
connect _cast_array_to_bits_expr_1[2], _array_literal_expr_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 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]
|
|
||||||
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_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_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]
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use bitvec::{order::Lsb0, view::BitView};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
assert_export_firrtl,
|
assert_export_firrtl,
|
||||||
firrtl::ExportOptions,
|
firrtl::ExportOptions,
|
||||||
|
formal::FormalInputKind,
|
||||||
memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask},
|
memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask},
|
||||||
module::{
|
module::{
|
||||||
instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc,
|
instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc,
|
||||||
|
|
@ -16,7 +17,12 @@ use fayalite::{
|
||||||
ty::SimValueDebug,
|
ty::SimValueDebug,
|
||||||
util::{RcWriter, ready_valid::queue},
|
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)]
|
#[hdl_module(outline_generated)]
|
||||||
pub fn connect_const() {
|
pub fn connect_const() {
|
||||||
|
|
@ -3610,3 +3616,200 @@ circuit sim_trace_as_string: %[[
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn enum_structural_eq() {
|
||||||
|
#[hdl]
|
||||||
|
let a: HdlOption<UInt<2>> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let b: HdlOption<UInt<2>> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let eq: Bool = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let structural_eq: Bool = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let bit_eq: Bool = m.output();
|
||||||
|
|
||||||
|
connect(eq, a.cmp_eq(b));
|
||||||
|
// explicitly use StructuralEq (though cmp_eq also uses it above)
|
||||||
|
connect(
|
||||||
|
structural_eq,
|
||||||
|
fayalite::expr::ops::StructuralEq::new(Expr::canonical(a), Expr::canonical(b)),
|
||||||
|
);
|
||||||
|
connect(bit_eq, a.cast_to_bits().cmp_eq(b.cast_to_bits()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enum_structural_eq() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let mut sim = Simulation::new(enum_structural_eq());
|
||||||
|
let _checked_vcd_output =
|
||||||
|
checked_vcd_output!(&mut sim, "tests/sim/expected/test_enum_structural_eq.vcd");
|
||||||
|
for a in 0..8u8 {
|
||||||
|
for b in 0..8u8 {
|
||||||
|
dbg!(a);
|
||||||
|
dbg!(b);
|
||||||
|
let a_sim_value = a.cast_to(UInt[3]).cast_bits_to(sim.io().a.ty());
|
||||||
|
let b_sim_value = b.cast_to(UInt[3]).cast_bits_to(sim.io().b.ty());
|
||||||
|
dbg!(&a_sim_value);
|
||||||
|
dbg!(&b_sim_value);
|
||||||
|
sim.write(sim.io().a, a_sim_value);
|
||||||
|
sim.write(sim.io().b, b_sim_value);
|
||||||
|
let a_with_zeroed_padding = if (a & 1) != 0 { a } else { 0 };
|
||||||
|
let b_with_zeroed_padding = if (b & 1) != 0 { b } else { 0 };
|
||||||
|
dbg!(a_with_zeroed_padding);
|
||||||
|
dbg!(b_with_zeroed_padding);
|
||||||
|
let expected_eq = a_with_zeroed_padding == b_with_zeroed_padding;
|
||||||
|
let expected_structural_eq = a_with_zeroed_padding == b_with_zeroed_padding;
|
||||||
|
let expected_bit_eq = a == b;
|
||||||
|
dbg!(expected_eq);
|
||||||
|
dbg!(expected_structural_eq);
|
||||||
|
dbg!(expected_bit_eq);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
assert_eq!(sim.read_bool(sim.io().eq), expected_eq);
|
||||||
|
assert_eq!(
|
||||||
|
sim.read_bool(sim.io().structural_eq),
|
||||||
|
expected_structural_eq
|
||||||
|
);
|
||||||
|
assert_eq!(sim.read_bool(sim.io().bit_eq), expected_bit_eq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let sim_debug = format!("{sim:#?}");
|
||||||
|
println!("#######\n{sim_debug}\n#######");
|
||||||
|
if sim_debug != include_str!("sim/expected/test_enum_structural_eq.txt") {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 38,
|
pc: 38,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -497,6 +498,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1759,5 +1761,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +76,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 5,
|
pc: 5,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -101,6 +102,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -186,5 +188,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -54,6 +54,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 2,
|
pc: 2,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -77,6 +78,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -138,5 +140,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +80,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 5,
|
pc: 5,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -106,6 +107,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -206,5 +208,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -180,6 +180,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 19,
|
pc: 19,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -216,6 +217,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -385,5 +387,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -162,6 +162,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 16,
|
pc: 16,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -197,6 +198,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -366,5 +368,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +72,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 4,
|
pc: 4,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -97,6 +98,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [],
|
base_targets: [],
|
||||||
uninitialized_ios: {},
|
uninitialized_ios: {},
|
||||||
|
|
@ -169,5 +171,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -409,6 +409,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 45,
|
pc: 45,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -465,6 +466,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -745,5 +747,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1184,6 +1184,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 133,
|
pc: 133,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -1324,6 +1325,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1955,5 +1957,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +44,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -67,6 +68,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -261,5 +263,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -72,6 +73,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -416,5 +418,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -407,6 +407,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 44,
|
pc: 44,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -464,6 +465,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -705,5 +707,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -2728,6 +2728,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 256,
|
pc: 256,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -3183,6 +3184,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -7927,5 +7929,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -494,6 +494,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 41,
|
pc: 41,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -579,6 +580,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1650,5 +1652,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -526,6 +526,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 52,
|
pc: 52,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -607,6 +608,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1285,5 +1287,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1336,6 +1336,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 129,
|
pc: 129,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1495,6 +1496,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -3345,5 +3347,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +187,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 17,
|
pc: 17,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -225,6 +226,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -577,5 +579,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +172,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 16,
|
pc: 16,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -215,6 +216,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -527,5 +529,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1083,6 +1083,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 134,
|
pc: 134,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1201,6 +1202,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2160,5 +2162,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1064,6 +1064,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 132,
|
pc: 132,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1180,6 +1181,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2139,5 +2141,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1093,6 +1093,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 136,
|
pc: 136,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1211,6 +1212,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2170,5 +2172,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1074,6 +1074,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 134,
|
pc: 134,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1190,6 +1191,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2149,5 +2151,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1098,6 +1098,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 135,
|
pc: 135,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1219,6 +1220,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2178,5 +2180,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1079,6 +1079,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 133,
|
pc: 133,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1198,6 +1199,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2157,5 +2159,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1108,6 +1108,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 137,
|
pc: 137,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1229,6 +1230,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2188,5 +2190,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1089,6 +1089,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 135,
|
pc: 135,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1208,6 +1209,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2167,5 +2169,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1125,6 +1125,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 139,
|
pc: 139,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1248,6 +1249,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2187,5 +2189,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1106,6 +1106,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 137,
|
pc: 137,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1227,6 +1228,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2166,5 +2168,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1135,6 +1135,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 141,
|
pc: 141,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1258,6 +1259,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2197,5 +2199,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1116,6 +1116,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 139,
|
pc: 139,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1237,6 +1238,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2176,5 +2178,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1104,6 +1104,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 135,
|
pc: 135,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1227,6 +1228,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2186,5 +2188,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1085,6 +1085,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 133,
|
pc: 133,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1206,6 +1207,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2165,5 +2167,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1114,6 +1114,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 137,
|
pc: 137,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1237,6 +1238,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2196,5 +2198,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -1095,6 +1095,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 135,
|
pc: 135,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -1216,6 +1217,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2175,5 +2177,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -636,6 +636,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 69,
|
pc: 69,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -725,6 +726,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1790,5 +1792,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +254,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 34,
|
pc: 34,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -293,6 +294,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -545,5 +547,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +60,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -87,6 +88,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -521,5 +523,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +60,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -87,6 +88,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -521,5 +523,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -375,6 +375,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 41,
|
pc: 41,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -475,6 +476,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -1768,5 +1770,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -512,6 +512,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 57,
|
pc: 57,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -591,6 +592,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -9726,5 +9728,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -72,6 +73,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -539,5 +541,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -72,6 +73,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -539,5 +541,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -72,6 +73,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -497,5 +499,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 0,
|
pc: 0,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
|
|
@ -72,6 +73,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -497,5 +499,6 @@ Simulation {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
|
|
@ -494,6 +494,7 @@ Simulation {
|
||||||
},
|
},
|
||||||
pc: 43,
|
pc: 43,
|
||||||
memory_write_log: [],
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
memories: StatePart {
|
memories: StatePart {
|
||||||
value: [
|
value: [
|
||||||
MemoryData {
|
MemoryData {
|
||||||
|
|
@ -570,6 +571,7 @@ Simulation {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
global_io: {},
|
||||||
main_module: SimulationModuleState {
|
main_module: SimulationModuleState {
|
||||||
base_targets: [
|
base_targets: [
|
||||||
Instance {
|
Instance {
|
||||||
|
|
@ -2250,5 +2252,6 @@ Simulation {
|
||||||
}),
|
}),
|
||||||
waiting_sensitivity_sets_by_address: {},
|
waiting_sensitivity_sets_by_address: {},
|
||||||
waiting_sensitivity_sets_by_compiled_value: {},
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
522
crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt
Normal file
522
crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt
Normal file
|
|
@ -0,0 +1,522 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 2,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 13,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<3>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<3>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
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:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x1,
|
||||||
|
},
|
||||||
|
1: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x0,
|
||||||
|
},
|
||||||
|
2: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
|
||||||
|
},
|
||||||
|
3: SliceInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
start: 1,
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
4: AndBigWithSmallImmediate {
|
||||||
|
dest: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
lhs: StatePartIndex<BigSlots>(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
5: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
|
||||||
|
},
|
||||||
|
6: SliceInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
start: 1,
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
7: CmpEq {
|
||||||
|
dest: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
||||||
|
rhs: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
||||||
|
},
|
||||||
|
8: CmpEq {
|
||||||
|
dest: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
rhs: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:9:1
|
||||||
|
9: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(8), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:2:1
|
||||||
|
10: AndBigWithSmallImmediate {
|
||||||
|
dest: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
lhs: StatePartIndex<BigSlots>(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
11: BranchIfSmallNeImmediate {
|
||||||
|
target: 14,
|
||||||
|
lhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
rhs: 0x0,
|
||||||
|
},
|
||||||
|
12: BranchIfSmallNeImmediate {
|
||||||
|
target: 14,
|
||||||
|
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
rhs: 0x0,
|
||||||
|
},
|
||||||
|
13: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
14: BranchIfSmallNeImmediate {
|
||||||
|
target: 17,
|
||||||
|
lhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
15: BranchIfSmallNeImmediate {
|
||||||
|
target: 17,
|
||||||
|
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
16: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:7:1
|
||||||
|
17: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(6), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:8:1
|
||||||
|
18: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
19: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 19,
|
||||||
|
memory_write_log: [],
|
||||||
|
assert_failed_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
3,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sim_only_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
global_io: {},
|
||||||
|
main_module: SimulationModuleState {
|
||||||
|
base_targets: [
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.a,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.b,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.eq,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.structural_eq,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.bit_eq,
|
||||||
|
],
|
||||||
|
uninitialized_ios: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.a,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.b,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.bit_eq,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.eq,
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::enum_structural_eq,
|
||||||
|
instantiated: Module {
|
||||||
|
name: enum_structural_eq,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.structural_eq,
|
||||||
|
},
|
||||||
|
did_initial_settle: true,
|
||||||
|
clocks_for_past: {},
|
||||||
|
},
|
||||||
|
extern_modules: [],
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "enum_structural_eq",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "a",
|
||||||
|
child: TraceEnumWithFields {
|
||||||
|
name: "a",
|
||||||
|
discriminant: TraceEnumDiscriminant {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "$tag",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
non_empty_fields: [
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "HdlSome",
|
||||||
|
ty: UInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "b",
|
||||||
|
child: TraceEnumWithFields {
|
||||||
|
name: "b",
|
||||||
|
discriminant: TraceEnumDiscriminant {
|
||||||
|
location: TraceScalarId(2),
|
||||||
|
name: "$tag",
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
non_empty_fields: [
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(3),
|
||||||
|
name: "HdlSome",
|
||||||
|
ty: UInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "eq",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(4),
|
||||||
|
name: "eq",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "structural_eq",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(5),
|
||||||
|
name: "structural_eq",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "bit_eq",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(6),
|
||||||
|
name: "bit_eq",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: EnumDiscriminant {
|
||||||
|
index: StatePartIndex<SmallSlots>(0),
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
ty: UInt<2>,
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(2),
|
||||||
|
kind: EnumDiscriminant {
|
||||||
|
index: StatePartIndex<SmallSlots>(1),
|
||||||
|
ty: Enum {
|
||||||
|
HdlNone,
|
||||||
|
HdlSome(UInt<2>),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(3),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(5),
|
||||||
|
ty: UInt<2>,
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(4),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(6),
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(5),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(7),
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(6),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(8),
|
||||||
|
},
|
||||||
|
maybe_changed: true,
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
clocks_triggered: [],
|
||||||
|
event_queue: EventQueue(EventQueueData {
|
||||||
|
instant: 64 μs,
|
||||||
|
events: {},
|
||||||
|
}),
|
||||||
|
waiting_sensitivity_sets_by_address: {},
|
||||||
|
waiting_sensitivity_sets_by_compiled_value: {},
|
||||||
|
asserts: [],
|
||||||
|
..
|
||||||
|
}
|
||||||
282
crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd
Normal file
282
crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module enum_structural_eq $end
|
||||||
|
$scope struct a $end
|
||||||
|
$var string 1 +LxwI \$tag $end
|
||||||
|
$var wire 2 {bf!u HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct b $end
|
||||||
|
$var string 1 O%@#" \$tag $end
|
||||||
|
$var wire 2 ]xpB, HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 1 Yp4xI eq $end
|
||||||
|
$var wire 1 >R/<6 structural_eq $end
|
||||||
|
$var wire 1 ,}=e] bit_eq $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
sHdlNone\x20(0) +LxwI
|
||||||
|
b0 {bf!u
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#2000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#3000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#4000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#5000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#6000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#7000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#8000000
|
||||||
|
sHdlSome\x20(1) +LxwI
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
#9000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#10000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#11000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#12000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
#13000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#14000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
#15000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#16000000
|
||||||
|
sHdlNone\x20(0) +LxwI
|
||||||
|
b1 {bf!u
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#17000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#18000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#19000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#20000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#21000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#22000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#23000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#24000000
|
||||||
|
sHdlSome\x20(1) +LxwI
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
#25000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#26000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
#27000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#28000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#29000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#30000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
#31000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#32000000
|
||||||
|
sHdlNone\x20(0) +LxwI
|
||||||
|
b10 {bf!u
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#33000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#34000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#35000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#36000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#37000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#38000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#39000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#40000000
|
||||||
|
sHdlSome\x20(1) +LxwI
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
#41000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#42000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
#43000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#44000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
#45000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#46000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#47000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#48000000
|
||||||
|
sHdlNone\x20(0) +LxwI
|
||||||
|
b11 {bf!u
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#49000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#50000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#51000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#52000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
#53000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
#54000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#55000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
0Yp4xI
|
||||||
|
0>R/<6
|
||||||
|
0,}=e]
|
||||||
|
#56000000
|
||||||
|
sHdlSome\x20(1) +LxwI
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b0 ]xpB,
|
||||||
|
#57000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#58000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b1 ]xpB,
|
||||||
|
#59000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#60000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b10 ]xpB,
|
||||||
|
#61000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
#62000000
|
||||||
|
sHdlNone\x20(0) O%@#"
|
||||||
|
b11 ]xpB,
|
||||||
|
#63000000
|
||||||
|
sHdlSome\x20(1) O%@#"
|
||||||
|
1Yp4xI
|
||||||
|
1>R/<6
|
||||||
|
1,}=e]
|
||||||
|
#64000000
|
||||||
855
crates/fayalite/tests/sim/expected/test_formal_counter.txt
Normal file
855
crates/fayalite/tests/sim/expected/test_formal_counter.txt
Normal 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: "",
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
}
|
||||||
290
crates/fayalite/tests/sim/expected/test_formal_counter.vcd
Normal file
290
crates/fayalite/tests/sim/expected/test_formal_counter.vcd
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -75,7 +75,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
@ -214,7 +214,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
@ -326,7 +326,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,11 @@
|
||||||
"$kind": "Opaque"
|
"$kind": "Opaque"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NameIdOrGlobal": {
|
||||||
|
"data": {
|
||||||
|
"$kind": "ManualImpl"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ScopedNameId": {
|
"ScopedNameId": {
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Struct",
|
"$kind": "Struct",
|
||||||
|
|
@ -1043,6 +1048,22 @@
|
||||||
"fold_where": "T: Fold<State>",
|
"fold_where": "T: Fold<State>",
|
||||||
"visit_where": "T: Visit<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::with_flags",
|
||||||
|
"lhs()": "Visible",
|
||||||
|
"rhs()": "Visible",
|
||||||
|
"flags()": "Opaque"
|
||||||
|
}
|
||||||
|
},
|
||||||
"BlockId": {
|
"BlockId": {
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Opaque"
|
"$kind": "Opaque"
|
||||||
|
|
@ -1277,7 +1298,9 @@
|
||||||
"RegSync": "Visible",
|
"RegSync": "Visible",
|
||||||
"RegAsync": "Visible",
|
"RegAsync": "Visible",
|
||||||
"Wire": "Visible",
|
"Wire": "Visible",
|
||||||
"Instance": "Visible"
|
"Instance": "Visible",
|
||||||
|
"FormalInput": "Visible",
|
||||||
|
"SimIoForGlobal": "Visible"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TargetChild": {
|
"TargetChild": {
|
||||||
|
|
@ -1349,6 +1372,21 @@
|
||||||
"generics": "<T: Type>",
|
"generics": "<T: Type>",
|
||||||
"fold_where": "T: Fold<State>",
|
"fold_where": "T: Fold<State>",
|
||||||
"visit_where": "T: Visit<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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ function main()
|
||||||
*/LICENSE.md|*/Notices.txt)
|
*/LICENSE.md|*/Notices.txt)
|
||||||
# copyright file
|
# 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
|
# file that can't contain copyright header
|
||||||
;;
|
;;
|
||||||
/.forgejo/workflows/*.yml|*/.gitignore|*.toml|*/Makefile|*/_CoqProject)
|
/.forgejo/workflows/*.yml|*/.gitignore|*.toml|*/Makefile|*/_CoqProject)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue