diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index f7ad68d..451bc7e 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle { let mut fields_expr_ne = vec![]; let mut fields_valueless_eq = vec![]; let mut fields_valueless_ne = vec![]; + let mut fields_structural_eq = vec![]; for field in fields.named() { let field_ident = field.ident(); let field_ty = field.ty(); @@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle { .push(parse_quote_spanned! {cmp_eq.span=> #field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty> }); + fields_structural_eq.push(quote_spanned! {cmp_eq.span=> + <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ + }); fields_value_eq.push(quote_spanned! {span=> ::fayalite::expr::HdlPartialEqImpl::cmp_value_eq( __lhs.#field_ident, @@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle { let expr_ne_body; let valueless_eq_body; let valueless_ne_body; + let structural_eq; if fields_len == 0 { value_eq_body = quote_spanned! {span=> true @@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle { valueless_ne_body = quote_spanned! {span=> ::fayalite::expr::Valueless::new(::fayalite::int::Bool) }; + structural_eq = quote_spanned! {span=> + true + }; } else { value_eq_body = quote_spanned! {span=> #(#fields_value_eq)&* @@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle { let __rhs = ::fayalite::expr::ValueType::ty(&__rhs); #(#fields_valueless_ne)|* }; + structural_eq = quote_spanned! {span=> + #(#fields_structural_eq)&&* + }; }; quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::expr::HdlPartialEqImpl for #target #type_generics #cmp_eq_where_clause { + const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq; + #[track_caller] fn cmp_value_eq( __lhs: Self, @@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { + if >::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 } @@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { + if >::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 } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index e9f013b..68fcc02 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum { #where_clause { #[allow(non_snake_case, dead_code)] - #vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> { + #vis fn #ident( + #self_token, + ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { ::fayalite::sim::value::SimValue::from_value( #self_token.#sim_builder_ty_field_ident, #sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()), @@ -929,8 +931,14 @@ impl ToTokens for ParsedEnum { impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics #where_clause { - fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result { - <#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f) + fn fmt( + &self, + f: &mut ::fayalite::__std::fmt::Formatter<'_>, + ) -> ::fayalite::__std::fmt::Result { + <#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display( + self, + f, + ) } } }.to_tokens(tokens); @@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum { let mut variants_value_eq = vec![]; let mut variants_expr_eq = vec![]; let mut fields_valueless_eq = vec![]; + let mut structural_eq: Option = None; for ( variant_index, ParsedVariant { @@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum { .push(parse_quote_spanned! {cmp_eq.span=> #field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty> }); + match &mut structural_eq { + Some(structural_eq) => { + structural_eq.extend(quote_spanned! {cmp_eq.span=> + && <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::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=> - (#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => { + ( + #sim_value_ident::#variant_ident(__lhs_field, _), + #sim_value_ident::#variant_ident(__rhs_field, _), + ) => { ::fayalite::expr::HdlPartialEqImpl::cmp_value_eq( __lhs.#variant_ident, ::fayalite::__std::borrow::Cow::Borrowed(__lhs_field), @@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum { else { ::fayalite::__std::unreachable!(); }; - ::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs)); + ::fayalite::module::connect( + __retval, + ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs), + ); } }); fields_valueless_eq.push(quote_spanned! {span=> @@ -1043,7 +1070,10 @@ impl ToTokens for ParsedEnum { } if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { variants_value_eq.push(quote_spanned! {span=> - (#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => { + ( + #sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), + #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown), + ) => { __lhs_unknown == __rhs_unknown } }); @@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum { } }; let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq"); + let structural_eq = structural_eq.unwrap_or_else(|| { + quote_spanned! {span=> + true + } + }); quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::expr::HdlPartialEqImpl for #target #type_generics #cmp_eq_where_clause { + const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq; + #[track_caller] fn cmp_value_eq( __lhs: Self, - __lhs_value: ::fayalite::__std::borrow::Cow<'_, ::SimValue>, + __lhs_value: ::fayalite::__std::borrow::Cow<'_, + ::SimValue>, __rhs: Self, - __rhs_value: ::fayalite::__std::borrow::Cow<'_, ::SimValue>, + __rhs_value: ::fayalite::__std::borrow::Cow<'_, + ::SimValue>, ) -> ::fayalite::__std::primitive::bool { match (&*__lhs_value, &*__rhs_value) { #(#variants_value_eq)* @@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool); + if >::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); let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs); #(#variants_expr_eq)* @@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum { type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = ::fayalite::module::Scope; - type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope; + type MatchVariantAndInactiveScope = + ::fayalite::enum_::EnumMatchVariantAndInactiveScope; type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter; fn match_variants( @@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum { ::fayalite::int::Bool } fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token))) + ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new( + ::fayalite::enum_::EnumType::variants(#self_token), + )) } #[track_caller] #[allow(non_snake_case)] @@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum { ::fayalite::__std::panic!("expected enum"); }; let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_); - ::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants"); + ::fayalite::__std::assert_eq!( + #variants_token.len(), + #variants_len, + "enum has wrong number of variants", + ); Self { #(#from_canonical_body_fields)* } @@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum { type SimBuilder = #sim_builder_ident #type_generics; fn match_activate_scope( v: ::MatchVariantAndInactiveScope, - ) -> (::MatchVariant, ::MatchActiveScope) { + ) -> ( + ::MatchVariant, + ::MatchActiveScope, + ) { let (#variant_access_token, scope) = v.activate(); ( 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 #where_clause { - fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result { + fn fmt( + &self, + f: &mut ::fayalite::__std::fmt::Formatter<'_>, + ) -> ::fayalite::__std::fmt::Result { <#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f) } } @@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum { &self, ty: #target #type_generics, ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) + ::fayalite::sim::value::SimValue::from_value( + ty, + ::fayalite::__std::clone::Clone::clone(self), + ) } fn into_sim_value_with_type( self, diff --git a/crates/fayalite/src/annotations.rs b/crates/fayalite/src/annotations.rs index 4ca84dd..252a0ce 100644 --- a/crates/fayalite/src/annotations.rs +++ b/crates/fayalite/src/annotations.rs @@ -238,7 +238,10 @@ impl TargetedAnnotation { } #[track_caller] pub fn assert_valid_target(target: Interned) { - 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 { self.target diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index fa754fd..95ecb8b 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -4,7 +4,7 @@ use crate::{ expr::{ 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}, intern::{Intern, Interned, LazyInterned}, @@ -367,6 +367,8 @@ impl HdlPartialEqImpl> for where Lhs: HdlPartialEqImpl, { + const TRY_STRUCTURAL_EQ: bool = >::TRY_STRUCTURAL_EQ; + fn cmp_value_eq( lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -387,6 +389,11 @@ where } fn cmp_expr_eq(lhs: Expr, rhs: Expr>) -> Expr { 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() .zip(rhs) .map(|(l, r)| l.cmp_eq(r)) @@ -396,6 +403,11 @@ where } fn cmp_expr_ne(lhs: Expr, rhs: Expr>) -> Expr { 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() .zip(rhs) .map(|(l, r)| l.cmp_ne(r)) diff --git a/crates/fayalite/src/build/graph.rs b/crates/fayalite/src/build/graph.rs index bed8829..e46f0a4 100644 --- a/crates/fayalite/src/build/graph.rs +++ b/crates/fayalite/src/build/graph.rs @@ -12,7 +12,7 @@ use crate::{ use eyre::{ContextCompat, eyre}; use petgraph::{ algo::{DfsSpace, kosaraju_scc, toposort}, - graph::DiGraph, + graph::{DiGraph, NodeIndex}, visit::{GraphBase, Visitable}, }; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq}; @@ -465,7 +465,7 @@ impl JobGraph { } }) .expect("we know there's a cycle"); - let cycle_set = HashSet::from_iter(cycle.iter().copied()); + let cycle_set = HashSet::::from_iter(cycle.iter().copied()); let job = cycle .into_iter() .find_map(|node_id| { @@ -701,7 +701,7 @@ impl JobGraph { job: DynJob, thread: ScopedJoinHandle<'scope, eyre::Result>>, } - let mut running_jobs = HashMap::default(); + let mut running_jobs = HashMap::::default(); let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel(); let mut next_finished_job = None; loop { diff --git a/crates/fayalite/src/build/verilog.rs b/crates/fayalite/src/build/verilog.rs index 7ce77ec..9c54ba8 100644 --- a/crates/fayalite/src/build/verilog.rs +++ b/crates/fayalite/src/build/verilog.rs @@ -211,7 +211,7 @@ impl ExternalCommand for UnadjustedVerilog { args.write_arg("-o"); args.write_interned_arg(unadjusted_verilog_file_name); if verilog_debug { - args.write_args(["-g", "--preserve-values=all"]); + args.write_args(["-g", "--preserve-values=named"]); } if let Some(dialect) = verilog_dialect { args.write_args(dialect.firtool_extra_args().iter().copied()); diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 5fad35c..5a97944 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -5,7 +5,7 @@ use crate::{ expr::{ CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType, Valueless, - ops::{ArrayLiteral, BundleLiteral}, + ops::{ArrayLiteral, BundleLiteral, StructuralEq}, value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue}, }, int::{Bool, DynSize}, @@ -708,6 +708,8 @@ macro_rules! impl_tuples { } } 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] fn cmp_value_eq( lhs: Self, @@ -725,6 +727,11 @@ macro_rules! impl_tuples { #[track_caller] fn cmp_expr_eq(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { + 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 ($($rhs_var,)*) = *rhs; ArrayLiteral::::new( @@ -737,6 +744,11 @@ macro_rules! impl_tuples { #[track_caller] fn cmp_expr_ne(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { + 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 ($($rhs_var,)*) = *rhs; ArrayLiteral::::new( diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index e235cd7..f9f239f 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -6,6 +6,7 @@ use crate::{ bundle::{Bundle, BundleType}, enum_::{Enum, EnumType}, expr::target::{GetTarget, Target}, + formal::FormalInput, int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{DynPortType, MemPort, PortType}, @@ -220,6 +221,7 @@ expr_enum! { CastBitsTo(ops::CastBitsTo), ToTraceAsString(ops::ToTraceAsString), TraceAsStringAsInner(ops::TraceAsStringAsInner), + StructuralEq(ops::StructuralEq), ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), @@ -227,6 +229,8 @@ expr_enum! { RegSync(Reg), RegAsync(Reg), MemPort(MemPort), + FormalInput(FormalInput), + SimIoForGlobal(ops::SimIoForGlobal), } } @@ -698,6 +702,7 @@ macro_rules! impl_hdl_cmp { impl_helper = $HdlCmpImplHelper:ident, $(impl_helper_base = $HdlCmpImplHelperBase:ident,)? impl_helper_sealed = $HdlCmpImplHelperSealed:ident, + $(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)? ] $vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>: ValueType $(+ $HdlCmpImplBase:ident)?> $(+ $HdlCmpBase:ident)? @@ -726,6 +731,8 @@ macro_rules! impl_hdl_cmp { } $vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? { + $(const $TRY_STRUCTURAL_EQ: bool;)? + $(#[track_caller] fn $cmp_value_fn( $cmp_value_lhs: Self, @@ -909,6 +916,7 @@ impl_hdl_cmp! { #[ impl_helper = HdlPartialEqImplHelper, impl_helper_sealed = HdlPartialEqImplHelperSealed, + try_structural_eq = TRY_STRUCTURAL_EQ, ] pub trait HdlPartialEq: ValueType > @@ -1908,3 +1916,19 @@ impl ToTraceAsStringImpl Result, NotALiteralExpr> { + Err(NotALiteralExpr) + } +} + +impl ToExpr for FormalInput { + fn to_expr(&self) -> Expr { + Expr { + __enum: ExprEnum::FormalInput(*self).intern_sized(), + __ty: self.ty(), + __flow: self.flow(), + } + } +} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index b2e20ad..7c5af38 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -17,11 +17,12 @@ use crate::{ }, value_category::ValueCategoryExpr, }, + formal::FormalInput, int::{ Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue, }, - intern::{Intern, Interned}, + intern::{Intern, Interned, MemoizeGeneric}, phantom_const::{PhantomConst, PhantomConstValue}, reset::{ AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset, @@ -2983,6 +2984,7 @@ macro_rules! impl_compare_op { #[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)] #[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)] #[type($Lhs:ty, $Rhs:ty)] + $(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])? #[trait($Trait:ident)] $( struct $name:ident; @@ -3044,6 +3046,7 @@ macro_rules! impl_compare_op { })* impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs { + $(const $TRY_STRUCTURAL_EQ: bool = true;)? $(fn $value_method( _lhs: Self, $lhs_compare_value: Cow<'_, ::SimValue>, @@ -3064,6 +3067,7 @@ impl_compare_op! { #[to_dyn_type(lhs => lhs, rhs => rhs)] #[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)] #[type(Bool, Bool)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3087,6 +3091,7 @@ impl_compare_op! { #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())] #[type(UIntType, UIntType)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3111,6 +3116,7 @@ impl_compare_op! { #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())] #[type(SIntType, SIntType)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3132,6 +3138,8 @@ impl_compare_op! { macro_rules! impl_compare_forwards_to_bool { ($ty:ident) => { impl HdlPartialEqImpl for $ty { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -4881,3 +4889,336 @@ impl ToExpr for TraceAsStringAsInner { } } } + +#[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> { + Some(Target::from(*self).intern_sized()) + } +} + +impl ToLiteralBits for SimIoForGlobal { + fn to_literal_bits(&self) -> Result, 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 { + 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, + rhs: Expr, + flags: StructuralEqFlags, + literal_bits: Result, NotALiteralExpr>, +} + +impl StructuralEq { + fn literal_eq( + ty: CanonicalType, + l: Interned, + r: Interned, + ) -> Result { + enum PairRefOrInternedBitSlice<'a> { + Ref(&'a BitSlice, &'a BitSlice), + Interned(Interned, Interned), + } + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize(CanonicalType); + impl MemoizeGeneric for MyMemoize { + type InputRef<'a> = (&'a BitSlice, &'a BitSlice); + type InputOwned = (Interned, Interned); + type InputCow<'a> = PairRefOrInternedBitSlice<'a>; + type Output = Result; + + 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::()[..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, rhs: Expr) -> Self { + Self::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT) + } + #[track_caller] + pub fn with_flags( + lhs: Expr, + rhs: Expr, + flags: StructuralEqFlags, + ) -> Self { + match Self::try_with_flags(lhs, rhs, flags) { + Ok(retval) => retval, + Err(e) => panic!("{e}"), + } + } + pub fn try_new( + lhs: Expr, + rhs: Expr, + ) -> Result { + Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT) + } + pub fn try_with_flags( + lhs: Expr, + rhs: Expr, + flags: StructuralEqFlags, + ) -> Result { + 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 { + self.lhs + } + pub fn rhs(self) -> Expr { + self.rhs + } + pub fn flags(self) -> StructuralEqFlags { + self.flags + } +} + +impl ToLiteralBits for StructuralEq { + fn to_literal_bits(&self) -> Result, 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 { + Expr { + __enum: ExprEnum::StructuralEq(*self).intern(), + __ty: Bool, + __flow: Flow::Source, + } + } +} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index 9016111..84d3ace 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -4,6 +4,7 @@ use crate::{ array::Array, bundle::{Bundle, BundleField}, expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr}, + formal::FormalInput, intern::{Intern, Interned}, memory::{DynPortType, MemPort}, module::{Instance, ModuleIO, TargetName}, @@ -62,7 +63,7 @@ pub struct TargetPathToTraceAsString { impl fmt::Display for TargetPathToTraceAsString { 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] #[to = instance] Instance(Instance), + #[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::Wire(v) => TargetName(v.scoped_name(), None), TargetBase::Instance(v) => TargetName(v.scoped_name(), None), + TargetBase::FormalInput(v) => TargetName(v.scoped_name(), None), + TargetBase::SimIoForGlobal(v) => TargetName(v.global().scoped_name(), None), } } pub fn canonical_ty(&self) -> CanonicalType { @@ -354,6 +365,21 @@ impl TargetBase { TargetBase::RegAsync(v) => v.ty(), TargetBase::Wire(v) => v.ty(), TargetBase::Instance(v) => v.ty().canonical(), + TargetBase::FormalInput(v) => v.ty(), + TargetBase::SimIoForGlobal(v) => v.ty(), + } + } + pub fn is_valid_annotation_target(&self) -> bool { + match self { + Self::ModuleIO(_) => true, + Self::MemPort(_) => true, + Self::Reg(_) => true, + Self::RegSync(_) => true, + Self::RegAsync(_) => true, + Self::Wire(_) => true, + Self::Instance(_) => true, + Self::FormalInput(_) => false, + Self::SimIoForGlobal(_) => false, } } } @@ -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] pub fn join(&self, path_element: Interned) -> Self { TargetChild::new(self.intern(), path_element).into() @@ -664,6 +700,18 @@ pub trait GetTarget { fn target(&self) -> Option>; } +impl GetTarget for Target { + fn target(&self) -> Option> { + Some(self.intern()) + } +} + +impl GetTarget for TargetBase { + fn target(&self) -> Option> { + Some(Target::Base(self.intern()).intern_sized()) + } +} + impl GetTarget for bool { fn target(&self) -> Option> { None diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 51aa040..cad55a8 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2,47 +2,42 @@ // See Notices.txt for copyright information #![allow(clippy::type_complexity)] use crate::{ - annotations::{ - Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation, - }, - array::Array, + annotations::{Annotation, IntoAnnotations, TargetedAnnotation}, build::{ToArgs, WriteArgs}, - bundle::{Bundle, BundleField, BundleType}, - clock::Clock, - enum_::{Enum, EnumType, EnumVariant}, + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, expr::{ - CastBitsTo, Expr, ExprEnum, ToExpr, ValueType, + CastToImpl, ExprEnum, ops::{self, VariantAccess}, target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, TargetPathTraceAsStringInner, }, }, - formal::FormalKind, - int::{Bool, DynSize, IntType, SIntValue, UInt, UIntValue}, + formal::{FormalInput, FormalInputKind, FormalKind}, + int::IntType, intern::{Intern, Interned}, - memory::{Mem, PortKind, PortName, ReadUnderWrite}, + memory::{PortKind, PortName}, module::{ AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Module, ModuleBody, ModuleIO, NameId, NameOptId, - NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, + ExternModuleParameterValue, ModuleBody, ModuleIO, NameId, NameOptId, NormalModuleBody, + ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, transform::{ simplify_enums::{SimplifyEnumsError, SimplifyEnumsKind, simplify_enums}, simplify_memories::simplify_memories, + visit::Folder, }, }, - reset::{AsyncReset, Reset, ResetType, SyncReset}, - source_location::SourceLocation, - ty::{CanonicalType, OpaqueSimValueSize, Type}, + prelude::*, + reset::ResetType, + ty::OpaqueSimValueSize, util::{ BitSliceWriteWithBase, DebugAsRawString, GenericConstBool, HashMap, HashSet, const_str_array_is_strictly_ascending, }, vendor::xilinx::XilinxAnnotation, }; -use bitvec::slice::BitSlice; use clap::value_parser; use num_traits::Signed; use serde::{Deserialize, Serialize}; @@ -50,6 +45,7 @@ use std::{ cell::{Cell, RefCell}, cmp::Ordering, collections::{BTreeMap, VecDeque}, + convert::Infallible, error::Error, ffi::OsString, fmt::{self, Write}, @@ -59,6 +55,7 @@ use std::{ ops::{ControlFlow, Range}, path::{Path, PathBuf}, rc::Rc, + sync::OnceLock, }; #[derive(Clone, Debug)] @@ -378,6 +375,91 @@ impl DefinitionsMap { } } +#[derive(Default)] +struct BlockDefinitionsCache { + array_literal_exprs: + RefCell, bool), String>>, + bundle_literal_exprs: RefCell>, + uninit_exprs: RefCell>, + cast_bundle_to_bits_exprs: RefCell>, + cast_enum_to_bits_exprs: RefCell>, + cast_array_to_bits_exprs: RefCell>, + cast_bits_to_bundle_exprs: RefCell>, + cast_bits_to_enum_exprs: RefCell>, + cast_bits_to_array_exprs: RefCell>, + cast_bits_to_phantom_const_exprs: RefCell>, + per_module_formal_inputs: RefCell>, + structural_eq_exprs: RefCell>, +} + +struct BlockDefinitions<'a> { + rc_definitions: RcDefinitions, + parent: Option<&'a BlockDefinitions<'a>>, + cache: BlockDefinitionsCache, +} + +impl<'a> BlockDefinitions<'a> { + fn new(parent: &'a BlockDefinitions<'a>) -> Self { + Self { + rc_definitions: RcDefinitions::default(), + parent: Some(parent), + cache: Default::default(), + } + } + fn module() -> Self { + Self { + rc_definitions: RcDefinitions::default(), + parent: None, + cache: Default::default(), + } + } + fn get_or_write_definition( + &self, + key: K, + field: impl Fn(&BlockDefinitionsCache) -> &RefCell>, + write_definition: impl FnOnce(BlockDefinitionsWriter<'_, '_>, &K) -> Result, + ) -> Result { + let mut current = self; + loop { + let field = field(¤t.cache).borrow(); + if let Some(retval) = field.get(&key) { + return Ok(retval.clone()); + } + let Some(parent) = current.parent else { + break; + }; + current = parent; + } + let retval = write_definition(BlockDefinitionsWriter { definitions: self }, &key)?; + Ok(field(&self.cache) + .borrow_mut() + .entry(key) + .or_insert(retval) + .clone()) + } + fn write_out(&self, indent: Indent<'_>, out: &mut String) { + self.rc_definitions.write_and_clear(indent, out); + } +} + +struct BlockDefinitionsWriter<'a, 'b> { + definitions: &'b BlockDefinitions<'a>, +} + +impl BlockDefinitionsWriter<'_, '_> { + fn add_definition_line(&self, v: impl fmt::Display) { + self.definitions.rc_definitions.add_definition_line(v); + } +} + +impl<'a> std::ops::Deref for BlockDefinitionsWriter<'a, '_> { + type Target = BlockDefinitions<'a>; + + fn deref(&self) -> &Self::Target { + &self.definitions + } +} + struct EnumDef { variants: RefCell, body: String, @@ -497,18 +579,19 @@ impl TypeState { } struct ModuleState { + module: Interned>, ns: Namespace, - definitions: RcDefinitions, match_arm_values: HashMap, Ident>, + block_definitions: Rc>, } -impl Default for ModuleState { - fn default() -> Self { - let definitions = RcDefinitions::default(); +impl ModuleState { + fn new(module: Interned>) -> Self { Self { + module, ns: Default::default(), - definitions, match_arm_values: Default::default(), + block_definitions: Rc::new(BlockDefinitions::module()), } } } @@ -744,6 +827,15 @@ struct FirrtlAnnotation { target: AnnotationTarget, } +struct ResetSourceLocation; + +impl Folder for ResetSourceLocation { + type Error = Infallible; + fn fold_source_location(&mut self, _v: SourceLocation) -> Result { + Ok(SourceLocation::builtin()) + } +} + struct Exporter<'a> { file_backend: &'a mut dyn WrappedFileBackendTrait, indent: Indent<'a>, @@ -876,7 +968,7 @@ impl<'a> Exporter<'a> { &mut self, value: Expr, to_ty: ToTy, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let from_ty = value.ty(); @@ -911,7 +1003,7 @@ impl<'a> Exporter<'a> { &mut self, firrtl_cast_fn: Option<&str>, value: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let value = self.expr(Expr::canonical(value), definitions, const_ty)?; @@ -925,7 +1017,7 @@ impl<'a> Exporter<'a> { &mut self, base: Expr, range: Range, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let base_width = base.ty().width(); @@ -943,73 +1035,95 @@ impl<'a> Exporter<'a> { fn array_literal_expr( &mut self, expr: ops::ArrayLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_array_literal_expr"); - let ty_str = self.type_state.ty(expr.ty())?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_str}")); - for (index, element) in expr.element_values().into_iter().enumerate() { - let element = self.expr(Expr::canonical(element), definitions, const_ty)?; - definitions.add_definition_line(format_args!("connect {ident}[{index}], {element}")); - } - if expr.element_values().is_empty() { - definitions.add_definition_line(format_args!("invalidate {ident}")); - } - Ok(ident.to_string()) + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.array_literal_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_array_literal_expr"); + let ty_str = self.type_state.ty(expr.ty())?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_str}")); + for (index, element) in expr.element_values().into_iter().enumerate() { + let element = self.expr(Expr::canonical(element), &definitions, const_ty)?; + definitions + .add_definition_line(format_args!("connect {ident}[{index}], {element}")); + } + if expr.element_values().is_empty() { + definitions.add_definition_line(format_args!("invalidate {ident}")); + } + Ok(ident.to_string()) + }, + ) } fn bundle_literal_expr( &mut self, expr: ops::BundleLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_bundle_literal_expr"); - let ty = expr.ty(); - let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty)?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); - for ( - field_value, - BundleField { - name, - flipped, - ty: _, + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.bundle_literal_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_bundle_literal_expr"); + let ty = expr.ty(); + let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty)?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); + for ( + field_value, + BundleField { + name, + flipped, + ty: _, + }, + ) in expr.field_values().into_iter().zip(ty.fields()) + { + debug_assert!( + !flipped, + "can't have bundle literal with flipped field -- \ + this should have been caught in BundleLiteral::new_unchecked" + ); + let name = bundle_ns.borrow_mut().get(name); + let field_value = + self.expr(Expr::canonical(field_value), &definitions, const_ty)?; + definitions + .add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); + } + if ty.fields().is_empty() { + definitions.add_definition_line(format_args!("invalidate {ident}")); + } + Ok(ident.to_string()) }, - ) in expr.field_values().into_iter().zip(ty.fields()) - { - debug_assert!( - !flipped, - "can't have bundle literal with flipped field -- this should have been caught in BundleLiteral::new_unchecked" - ); - let name = bundle_ns.borrow_mut().get(name); - let field_value = self.expr(Expr::canonical(field_value), definitions, const_ty)?; - definitions.add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); - } - if ty.fields().is_empty() { - definitions.add_definition_line(format_args!("invalidate {ident}")); - } - Ok(ident.to_string()) + ) } fn uninit_expr( &mut self, expr: ops::Uninit, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_uninit_expr"); - let ty = expr.ty(); - let ty_ident = self.type_state.ty(ty)?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); - definitions.add_definition_line(format_args!("invalidate {ident}")); - Ok(ident.to_string()) + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.uninit_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_uninit_expr"); + let ty = expr.ty(); + let ty_ident = self.type_state.ty(ty)?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); + definitions.add_definition_line(format_args!("invalidate {ident}")); + Ok(ident.to_string()) + }, + ) } fn enum_literal_expr( &mut self, expr: ops::EnumLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let variant_expr = expr @@ -1022,175 +1136,198 @@ impl<'a> Exporter<'a> { &mut self, value_str: String, ty: Bundle, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.fields().is_empty() { - return Ok("UInt<0>(0)".into()); - } - if let [field] = *ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - return self.expr_cast_to_bits( - format!("{value_str}.{field_ident}"), - field.ty, - definitions, - extra_indent, - ); - } - let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( - |&BundleField { - name, - flipped: _, - ty: field_ty, - }| BundleField { - name, - flipped: false, - ty: UInt[field_ty.bit_width()].canonical(), + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bundle_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.fields().is_empty() { + return Ok("UInt<0>(0)".into()); + } + if let [field] = *ty.fields() { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + return self.expr_cast_to_bits( + format!("{value_str}.{field_ident}"), + field.ty, + &definitions, + extra_indent, + ); + } + let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( + |&BundleField { + name, + flipped: _, + ty: field_ty, + }| BundleField { + name, + flipped: false, + ty: UInt[field_ty.bit_width()].canonical(), + }, + ))); + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let ident = self.module.ns.make_new("_cast_bundle_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {ident}: {flattened_ty_ident}" + )); + let mut cat_expr = None; + for field in ty.fields() { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let flattened_field_ident = self + .type_state + .get_bundle_field(flattened_bundle_ty, field.name)?; + let field_bits = self.expr_cast_to_bits( + format!("{value_str}.{field_ident}"), + field.ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {ident}.{flattened_field_ident}, {field_bits}" + )); + cat_expr = Some(if let Some(cat_expr) = cat_expr { + format!("cat({ident}.{flattened_field_ident}, {cat_expr})") + } else { + format!("{ident}.{flattened_field_ident}") + }); + } + let retval = self.module.ns.make_new("_cast_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width + )); + let cat_expr = cat_expr.expect("bundle already checked to have fields"); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {cat_expr}" + )); + Ok(retval.to_string()) }, - ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; - let ident = self.module.ns.make_new("_cast_bundle_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {ident}: {flattened_ty_ident}" - )); - let mut cat_expr = None; - for field in ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - let flattened_field_ident = self - .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; - let field_bits = self.expr_cast_to_bits( - format!("{value_str}.{field_ident}"), - field.ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {ident}.{flattened_field_ident}, {field_bits}" - )); - cat_expr = Some(if let Some(cat_expr) = cat_expr { - format!("cat({ident}.{flattened_field_ident}, {cat_expr})") - } else { - format!("{ident}.{flattened_field_ident}") - }); - } - let retval = self.module.ns.make_new("_cast_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - let cat_expr = cat_expr.expect("bundle already checked to have fields"); - definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + ) } fn expr_cast_enum_to_bits( &mut self, value_str: String, ty: Enum, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.variants().is_empty() { - return Ok("UInt<0>(0)".into()); - } - let retval = self.module.ns.make_new("_cast_enum_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:")); - let _match_arms_indent = extra_indent.push(); - for (variant_index, variant) in ty.variants().into_iter().enumerate() { - if let Some(variant_ty) = variant.ty { - let variant_value = self - .module - .ns - .make_new(&format!("_cast_enum_to_bits_expr_{}", variant.name)); + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_enum_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.variants().is_empty() { + return Ok("UInt<0>(0)".into()); + } + let retval = self.module.ns.make_new("_cast_enum_to_bits_expr"); definitions.add_definition_line(format_args!( - "{extra_indent}{}({variant_value}):", - self.type_state.get_enum_variant(ty, variant.name)?, + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width )); - let _match_arm_indent = extra_indent.push(); - let variant_bits = self.expr_cast_to_bits( - variant_value.to_string(), - variant_ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, pad(cat({variant_bits}, UInt<{}>({variant_index})), {})", - ty.discriminant_bit_width(), - ty.type_properties().bit_width, - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}{}:", - self.type_state.get_enum_variant(ty, variant.name)?, - )); - let _match_arm_indent = extra_indent.push(); - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, UInt<{}>({variant_index})", - ty.type_properties().bit_width, - )); - } - } - Ok(retval.to_string()) + definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:")); + let _match_arms_indent = extra_indent.push(); + for (variant_index, variant) in ty.variants().into_iter().enumerate() { + if let Some(variant_ty) = variant.ty { + let variant_value = self + .module + .ns + .make_new(&format!("_cast_enum_to_bits_expr_{}", variant.name)); + definitions.add_definition_line(format_args!( + "{extra_indent}{}({variant_value}):", + self.type_state.get_enum_variant(ty, variant.name)?, + )); + let _match_arm_indent = extra_indent.push(); + let variant_bits = self.expr_cast_to_bits( + variant_value.to_string(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, \ + pad(cat({variant_bits}, UInt<{}>({variant_index})), {})", + ty.discriminant_bit_width(), + ty.type_properties().bit_width, + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}{}:", + self.type_state.get_enum_variant(ty, variant.name)?, + )); + let _match_arm_indent = extra_indent.push(); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, UInt<{}>({variant_index})", + ty.type_properties().bit_width, + )); + } + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_array_to_bits( &mut self, value_str: String, ty: Array, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.is_empty() { - return Ok("UInt<0>(0)".into()); - } - if ty.len() == 1 { - return self.expr_cast_to_bits( - value_str + "[0]", - ty.element(), - definitions, - extra_indent, - ); - } - let element_width = ty.element().bit_width(); - let ident = self.module.ns.make_new("_cast_array_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {ident}: UInt<{element_width}>[{}]", - ty.len(), - )); - let mut cat_expr = None; - for index in 0..ty.len() { - let element_bits = self.expr_cast_to_bits( - format!("{value_str}[{index}]"), - ty.element(), - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {ident}[{index}], {element_bits}" - )); - cat_expr = Some(if let Some(cat_expr) = cat_expr { - format!("cat({ident}[{index}], {cat_expr})") - } else { - format!("{ident}[{index}]") - }); - } - let retval = self.module.ns.make_new("_cast_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - let cat_expr = cat_expr.expect("array already checked to have elements"); - definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_array_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.is_empty() { + return Ok("UInt<0>(0)".into()); + } + if ty.len() == 1 { + return self.expr_cast_to_bits( + value_str.clone() + "[0]", + ty.element(), + &definitions, + extra_indent, + ); + } + let element_width = ty.element().bit_width(); + let ident = self.module.ns.make_new("_cast_array_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {ident}: UInt<{element_width}>[{}]", + ty.len(), + )); + let mut cat_expr = None; + for index in 0..ty.len() { + let element_bits = self.expr_cast_to_bits( + format!("{value_str}[{index}]"), + ty.element(), + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {ident}[{index}], {element_bits}" + )); + cat_expr = Some(if let Some(cat_expr) = cat_expr { + format!("cat({ident}[{index}], {cat_expr})") + } else { + format!("{ident}[{index}]") + }); + } + let retval = self.module.ns.make_new("_cast_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width + )); + let cat_expr = cat_expr.expect("array already checked to have elements"); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {cat_expr}" + )); + Ok(retval.to_string()) + }, + ) } fn expr_cast_to_bits( &mut self, value_str: String, ty: CanonicalType, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { match ty.unwrap_transparent_types() { @@ -1219,195 +1356,230 @@ impl<'a> Exporter<'a> { &mut self, value_str: String, ty: Bundle, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let (ty_ident, _) = self.type_state.bundle_def(ty)?; - let retval = self.module.ns.make_new("_cast_bits_to_bundle_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); - if ty.fields().is_empty() { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( - |&BundleField { - name, - flipped: _, - ty: field_ty, - }| BundleField { - name, - flipped: false, - ty: UInt[field_ty.bit_width()].canonical(), - }, - ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; - let flattened_ident = self - .module - .ns - .make_new("_cast_bits_to_bundle_expr_flattened"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {flattened_ident}: {flattened_ty_ident}" - )); - for ( - field, - OpaqueSimValueSize { - bit_width: field_offset, - sim_only_values_len: _, - }, - ) in ty.fields().into_iter().zip(ty.field_offsets()) - { - let flattened_field_ident = self - .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - if let Some(field_bit_width_minus_one) = field.ty.bit_width().checked_sub(1usize) { + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_bundle_exprs, + |definitions, &(ref value_str, ty)| { + let (ty_ident, _) = self.type_state.bundle_def(ty)?; + let retval = self.module.ns.make_new("_cast_bits_to_bundle_expr"); + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); + if ty.fields().is_empty() { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( + |&BundleField { + name, + flipped: _, + ty: field_ty, + }| BundleField { + name, + flipped: false, + ty: UInt[field_ty.bit_width()].canonical(), + }, + ))); + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let flattened_ident = self + .module + .ns + .make_new("_cast_bits_to_bundle_expr_flattened"); definitions.add_definition_line(format_args!( - "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, bits({value_str}, {}, {field_offset})", - field_offset + field_bit_width_minus_one + "{extra_indent}wire {flattened_ident}: {flattened_ty_ident}" )); - } else { - definitions.add_definition_line(format_args!( + for ( + field, + OpaqueSimValueSize { + bit_width: field_offset, + sim_only_values_len: _, + }, + ) in ty.fields().into_iter().zip(ty.field_offsets()) + { + let flattened_field_ident = self + .type_state + .get_bundle_field(flattened_bundle_ty, field.name)?; + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + if let Some(field_bit_width_minus_one) = + field.ty.bit_width().checked_sub(1usize) + { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, \ + bits({value_str}, {}, {field_offset})", + field_offset + field_bit_width_minus_one + )); + } else { + definitions.add_definition_line(format_args!( "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, UInt<0>(0)" )); - } - let field_value = self.expr_cast_bits_to( - format!("{flattened_ident}.{flattened_field_ident}"), - field.ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}.{field_ident}, {field_value}" - )); - } - Ok(retval.to_string()) + } + let field_value = self.expr_cast_bits_to( + format!("{flattened_ident}.{flattened_field_ident}"), + field.ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}.{field_ident}, {field_value}" + )); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to_enum( &mut self, value_str: String, ty: Enum, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let (ty_ident, enum_def) = self.type_state.enum_def(ty)?; - let retval = self.module.ns.make_new("_cast_bits_to_enum_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); - if ty.variants().is_empty() { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - if let [variant] = *ty.variants() { - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; - if let Some(variant_ty) = variant.ty { - let variant_value = - self.expr_cast_bits_to(value_str, variant_ty, definitions, extra_indent)?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", - enum_def.body - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant})", - enum_def.body - )); - } - return Ok(retval.to_string()); - } - let discriminant_bit_width = ty.discriminant_bit_width(); - let body_bit_width = ty.type_properties().bit_width - discriminant_bit_width; - let body_ident = self.module.ns.make_new("_cast_bits_to_enum_expr_body"); - let body_value = if body_bit_width != 0 { - definitions.add_definition_line(format_args!( - "{extra_indent}wire {body_ident}: UInt<{body_bit_width}>" - )); - definitions.add_definition_line(format_args!( - "{extra_indent}connect {body_ident}, head({value_str}, {body_bit_width})" - )); - body_ident.to_string() - } else { - "UInt<0>(0)".into() - }; - for (variant_index, variant) in ty.variants().into_iter().enumerate() { - let when_cond = format!( - "eq(UInt<{discriminant_bit_width}>({variant_index}), tail({value_str}, {body_bit_width}))" - ); - if variant_index == ty.variants().len() - 1 { - definitions.add_definition_line(format_args!("{extra_indent}else:")); - } else if variant_index == 0 { - definitions.add_definition_line(format_args!("{extra_indent}when {when_cond}:")); - } else { + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_enum_exprs, + |definitions, &(ref value_str, ty)| { + let (ty_ident, enum_def) = self.type_state.enum_def(ty)?; + let retval = self.module.ns.make_new("_cast_bits_to_enum_expr"); definitions - .add_definition_line(format_args!("{extra_indent}else when {when_cond}:")); - } - let when_pushed_indent = extra_indent.push(); - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; - if let Some(variant_ty) = variant.ty { - let variant_value = self.expr_cast_bits_to( - body_value.clone(), - variant_ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", - enum_def.body - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant})", - enum_def.body - )); - } - drop(when_pushed_indent); - } - Ok(retval.to_string()) + .add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); + if ty.variants().is_empty() { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + if let [variant] = *ty.variants() { + let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + if let Some(variant_ty) = variant.ty { + let variant_value = self.expr_cast_bits_to( + value_str.clone(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", + enum_def.body + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant})", + enum_def.body + )); + } + return Ok(retval.to_string()); + } + let discriminant_bit_width = ty.discriminant_bit_width(); + let body_bit_width = ty.type_properties().bit_width - discriminant_bit_width; + let body_ident = self.module.ns.make_new("_cast_bits_to_enum_expr_body"); + let body_value = if body_bit_width != 0 { + definitions.add_definition_line(format_args!( + "{extra_indent}wire {body_ident}: UInt<{body_bit_width}>" + )); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {body_ident}, head({value_str}, {body_bit_width})" + )); + body_ident.to_string() + } else { + "UInt<0>(0)".into() + }; + for (variant_index, variant) in ty.variants().into_iter().enumerate() { + let when_cond = format!( + "eq(UInt<{discriminant_bit_width}>({variant_index}), \ + tail({value_str}, {body_bit_width}))" + ); + if variant_index == ty.variants().len() - 1 { + definitions.add_definition_line(format_args!("{extra_indent}else:")); + } else if variant_index == 0 { + definitions + .add_definition_line(format_args!("{extra_indent}when {when_cond}:")); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}else when {when_cond}:" + )); + } + let when_pushed_indent = extra_indent.push(); + let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + if let Some(variant_ty) = variant.ty { + let variant_value = self.expr_cast_bits_to( + body_value.clone(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", + enum_def.body + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant})", + enum_def.body + )); + } + drop(when_pushed_indent); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to_array( &mut self, value_str: String, ty: Array, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let retval = self.module.ns.make_new("_cast_bits_to_array_expr"); - let array_ty = self.type_state.ty(ty)?; - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}")); - let element_bit_width = ty.element().bit_width(); - if ty.is_empty() || element_bit_width == 0 { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - let flattened_ident = self - .module - .ns - .make_new("_cast_bits_to_array_expr_flattened"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {flattened_ident}: UInt<{element_bit_width}>[{}]", - ty.len(), - )); - for index in 0..ty.len() { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {flattened_ident}[{index}], bits({value_str}, {}, {})", - element_bit_width * index + element_bit_width - 1, - element_bit_width * index, - )); - let element_value = self.expr_cast_bits_to( - format!("{flattened_ident}[{index}]"), - ty.element(), - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}[{index}], {element_value}" - )); - } - Ok(retval.to_string()) + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_array_exprs, + |definitions, &(ref value_str, ty)| { + let retval = self.module.ns.make_new("_cast_bits_to_array_expr"); + let array_ty = self.type_state.ty(ty)?; + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}")); + let element_bit_width = ty.element().bit_width(); + if ty.is_empty() || element_bit_width == 0 { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + let flattened_ident = self + .module + .ns + .make_new("_cast_bits_to_array_expr_flattened"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {flattened_ident}: UInt<{element_bit_width}>[{}]", + ty.len(), + )); + for index in 0..ty.len() { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {flattened_ident}[{index}], \ + bits({value_str}, {}, {})", + element_bit_width * index + element_bit_width - 1, + element_bit_width * index, + )); + let element_value = self.expr_cast_bits_to( + format!("{flattened_ident}[{index}]"), + ty.element(), + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}[{index}], {element_value}" + )); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to( &mut self, value_str: String, ty: CanonicalType, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { match ty.unwrap_transparent_types() { @@ -1427,12 +1599,18 @@ impl<'a> Exporter<'a> { CanonicalType::AsyncReset(_) => Ok(format!("asAsyncReset({value_str})")), CanonicalType::SyncReset(_) => Ok(value_str), CanonicalType::Reset(_) => unreachable!("Reset is not bit castable to"), - CanonicalType::PhantomConst(_) => { - let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } + CanonicalType::PhantomConst(ty) => definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_phantom_const_exprs, + |definitions, &(ref _value_str, _ty)| { + let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + Ok(retval.to_string()) + }, + ), CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), } @@ -1441,7 +1619,7 @@ impl<'a> Exporter<'a> { &mut self, func: &str, arg: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { Ok(format!( @@ -1454,7 +1632,7 @@ impl<'a> Exporter<'a> { func: &str, lhs: Expr, rhs: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { Ok(format!( @@ -1463,10 +1641,281 @@ impl<'a> Exporter<'a> { rhs = self.expr(Expr::canonical(rhs), definitions, const_ty)?, )) } + #[hdl] + fn expr_formal_input(&mut self, formal_input: FormalInput, const_ty: bool) -> Result { + let definitions = self.module.block_definitions.clone(); + definitions.get_or_write_definition( + (formal_input, const_ty), + |c| &c.per_module_formal_inputs, + |definitions, &(formal_input, const_ty)| match formal_input.kind() { + FormalInputKind::FormalGlobalClock => { + let reg = Reg::new_unchecked( + ScopedNameId(self.module.module.name_id().into(), formal_input.name_id()), + formal_input.source_location(), + Bool, + #[hdl] + ClockDomain { + clk: false.to_clock(), + rst: false.to_sync_reset(), + }, + None, + ); + let module_name = self.global_ns.get(self.module.module.name_id()); + self.targeted_annotations( + module_name, + vec![], + &Vec::from_iter( + [ + SVAttributeAnnotation { + text: "gclk".intern(), + } + .into_annotations(), + DontTouchAnnotation.into_annotations(), + ] + .into_annotations() + .map(|a| { + TargetedAnnotation::new( + Target::from(reg.canonical()).intern_sized(), + a, + ) + }), + ), + )?; + definitions.add_definition_line(self.reg(reg.canonical(), &definitions)?); + self.expr( + Expr::canonical(reg.to_expr().to_clock()), + &definitions, + const_ty, + ) + } + FormalInputKind::FormalReset => { + #[hdl_module(extern)] + fn formal_reset() { + #[hdl] + let rst: SyncReset = m.output(); + m.annotate_module(BlackBoxInlineAnnotation { + path: "fayalite_formal_reset.v".intern(), + text: r"module __fayalite_formal_reset(output rst); + assign rst = $initstate; +endmodule +" + .intern(), + }); + m.verilog_name("__fayalite_formal_reset"); + } + static MOD: OnceLock>> = OnceLock::new(); + let formal_reset = Instance::new_unchecked( + ScopedNameId(self.module.module.name_id().into(), formal_input.name_id()), + *MOD.get_or_init(|| { + let module = formal_reset(); + let Ok(module) = ResetSourceLocation.fold_module(*module); + module.intern_sized() + }), + formal_input.source_location(), + ); + definitions.add_definition_line(self.instance(formal_reset.canonical())?); + self.expr( + Expr::canonical(formal_reset.to_expr().rst), + &definitions, + const_ty, + ) + } + FormalInputKind::AnyConst + | FormalInputKind::AnySeq + | FormalInputKind::AllConst + | FormalInputKind::AllSeq => { + match formal_input.ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) => {} + _ => panic!( + "{}() -- unsupported type: {formal_input:#?}", + formal_input.name() + ), + } + if formal_input.ty().size().is_empty() { + return self.expr(formal_input.ty().uninit(), &definitions, const_ty); + } + let reg = Reg::new_unchecked( + ScopedNameId(self.module.module.name_id().into(), formal_input.name_id()), + formal_input.source_location(), + formal_input.ty(), + #[hdl] + ClockDomain { + clk: false.to_clock(), + rst: false.to_sync_reset(), + }, + None, + ); + let module_name = self.global_ns.get(self.module.module.name_id()); + self.targeted_annotations( + module_name, + vec![], + &Vec::from_iter( + [ + SVAttributeAnnotation { + text: match formal_input.kind() { + FormalInputKind::AnyConst => "anyconst".intern(), + FormalInputKind::AnySeq => "anyseq".intern(), + FormalInputKind::AllConst => "allconst".intern(), + FormalInputKind::AllSeq => "allseq".intern(), + _ => unreachable!(), + }, + } + .into_annotations(), + DontTouchAnnotation.into_annotations(), + ] + .into_annotations() + .map(|a| TargetedAnnotation::new(Target::from(reg).intern_sized(), a)), + ), + )?; + definitions.add_definition_line(self.reg(reg, &definitions)?); + self.expr(Expr::canonical(reg.to_expr()), &definitions, const_ty) + } + }, + ) + } + fn expr_structural_eq_bit>( + &mut self, + lhs: Expr, + rhs: Expr, + definitions: &BlockDefinitions<'_>, + const_ty: bool, + ) -> Result { + self.expr_binary( + "eq", + Expr::::from_canonical(lhs).cast_to(Bool), + Expr::::from_canonical(rhs).cast_to(Bool), + definitions, + const_ty, + ) + } + fn expr_structural_eq( + &mut self, + ty: CanonicalType, + lhs: String, + rhs: String, + definitions: &BlockDefinitions<'_>, + const_ty: bool, + ) -> Result { + match ty { + CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => { + Ok(format!("eq({lhs}, {rhs})")) + } + CanonicalType::Array(ty) => { + if ty.len() == 1 { + return self.expr_structural_eq( + ty.element(), + lhs + "[0]", + rhs + "[0]", + definitions, + const_ty, + ); + } else if ty.is_empty() { + return Ok(self.bool_literal(true)); + } + definitions.get_or_write_definition( + (lhs, rhs), + |c| &c.structural_eq_exprs, + |definitions, (lhs, rhs)| { + let mut retval = None; + for array_index in 0..ty.len() { + let element_eq = self.expr_structural_eq( + ty.element(), + format!("{lhs}[{array_index}]"), + format!("{rhs}[{array_index}]"), + &definitions, + const_ty, + )?; + retval = match retval { + Some(old_eq) => { + let ident = self.module.ns.make_new("_array_structural_eq"); + definitions + .add_definition_line(format_args!("wire {ident}: UInt<1>")); + definitions.add_definition_line(format_args!( + "connect {ident}, and({old_eq}, {element_eq})" + )); + Some(ident.to_string()) + } + None => Some(element_eq), + }; + } + Ok(retval.expect("known to be Some")) + }, + ) + } + CanonicalType::Enum(ty) => { + let lhs = self.expr_cast_enum_to_bits( + lhs, + ty, + definitions, + Indent { + indent_depth: &Cell::new(0), + indent: self.indent.indent, + }, + )?; + let rhs = self.expr_cast_enum_to_bits( + rhs, + ty, + definitions, + Indent { + indent_depth: &Cell::new(0), + indent: self.indent.indent, + }, + )?; + Ok(format!("eq({lhs}, {rhs})")) + } + CanonicalType::Bundle(ty) => { + let fields = ty.fields(); + if fields.is_empty() { + return Ok(self.bool_literal(true)); + } + definitions.get_or_write_definition( + (lhs, rhs), + |c| &c.structural_eq_exprs, + |definitions, (lhs, rhs)| { + let mut retval = None; + for field in fields { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let field_eq = self.expr_structural_eq( + field.ty, + format!("{lhs}.{field_ident}"), + format!("{rhs}.{field_ident}"), + &definitions, + const_ty, + )?; + retval = match retval { + Some(old_eq) => { + let ident = self.module.ns.make_new("_bundle_structural_eq"); + definitions + .add_definition_line(format_args!("wire {ident}: UInt<1>")); + definitions.add_definition_line(format_args!( + "connect {ident}, and({old_eq}, {field_eq})" + )); + Some(ident.to_string()) + } + None => Some(field_eq), + }; + } + Ok(retval.expect("known to be Some")) + }, + ) + } + CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => Ok(format!("eq(asUInt({lhs}), asUInt({rhs}))")), + CanonicalType::PhantomConst(_) => Ok(self.bool_literal(true)), + CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + CanonicalType::TraceAsString(ty) => { + self.expr_structural_eq(ty.inner_ty(), lhs, rhs, definitions, const_ty) + } + } + } fn expr( &mut self, expr: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { match *Expr::expr_enum(expr) { @@ -1806,6 +2255,13 @@ impl<'a> Exporter<'a> { ExprEnum::TraceAsStringAsInner(expr) => { self.expr(Expr::canonical(expr.arg()), definitions, const_ty) } + ExprEnum::StructuralEq(expr) => { + let ty = expr.lhs().ty(); + assert_eq!(ty, expr.rhs().ty()); + let lhs = self.expr(expr.lhs(), definitions, const_ty)?; + let rhs = self.expr(expr.rhs(), definitions, const_ty)?; + self.expr_structural_eq(ty, lhs, rhs, definitions, const_ty) + } ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()), ExprEnum::Instance(expr) => { assert!(!const_ty, "not a constant"); @@ -1833,6 +2289,10 @@ impl<'a> Exporter<'a> { let port_name = Ident::from(expr.port_name()); Ok(format!("{mem_name}.{port_name}")) } + ExprEnum::FormalInput(expr) => self.expr_formal_input(expr, const_ty), + ExprEnum::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } } } fn write_mem_init( @@ -1947,6 +2407,9 @@ impl<'a> Exporter<'a> { TargetBase::RegAsync(v) => self.module.ns.get(v.name_id()), TargetBase::Wire(v) => self.module.ns.get(v.name_id()), TargetBase::Instance(v) => self.module.ns.get(v.name_id()), + TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => { + unreachable!("base.is_valid_annotation_target() is known to be false") + } }; Ok(AnnotationTargetRef { base, segments }) } @@ -2058,47 +2521,60 @@ impl<'a> Exporter<'a> { drop(memory_indent); Ok(body) } - fn stmt_reg( + fn reg( &mut self, - stmt_reg: StmtReg, - module_name: Ident, - definitions: &RcDefinitions, - body: &mut String, - ) -> Result<()> { - let StmtReg { annotations, reg } = stmt_reg; - let indent = self.indent; - self.targeted_annotations(module_name, vec![], &annotations)?; + reg: Reg, + definitions: &BlockDefinitions<'_>, + ) -> Result { let name = self.module.ns.get(reg.name_id()); let ty = self.type_state.ty(reg.ty())?; let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false)?; if let Some(init) = reg.init() { let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false)?; let init = self.expr(init, definitions, false)?; - writeln!( - body, - "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", + Ok(format!( + "regreset {name}: {ty}, {clk}, {rst}, {init}{}", FileInfo::new(reg.source_location()), - ) - .unwrap(); + )) } else { - writeln!( - body, - "{indent}reg {name}: {ty}, {clk}{}", + Ok(format!( + "reg {name}: {ty}, {clk}{}", FileInfo::new(reg.source_location()), - ) - .unwrap(); + )) } + } + fn stmt_reg( + &mut self, + stmt_reg: StmtReg, + module_name: Ident, + definitions: &BlockDefinitions<'_>, + body: &mut String, + ) -> Result<()> { + let StmtReg { annotations, reg } = stmt_reg; + let indent = self.indent; + self.targeted_annotations(module_name, vec![], &annotations)?; + writeln!(body, "{indent}{}", self.reg(reg, definitions)?).unwrap(); Ok(()) } + fn instance(&mut self, instance: Instance) -> Result { + let name = self.module.ns.get(instance.name_id()); + let instantiated = instance.instantiated(); + self.add_module(instantiated); + let module_name = self.global_ns.get(instantiated.name_id()); + Ok(format!( + "inst {name} of {module_name}{}", + FileInfo::new(instance.source_location()), + )) + } fn block( &mut self, module: Interned>, block: Block, _block_indent: &PushIndent<'_>, - definitions: Option, + parent_definitions: &BlockDefinitions, ) -> Result { let indent = self.indent; - let definitions = definitions.unwrap_or_default(); + let definitions = BlockDefinitions::new(parent_definitions); let mut body = String::new(); let mut out = String::new(); let Block { memories, stmts } = block; @@ -2175,7 +2651,7 @@ impl<'a> Exporter<'a> { .unwrap(); pushed_indent = indent.push(); let then_block_str = - self.block(module, then_block, &pushed_indent, None)?; + self.block(module, then_block, &pushed_indent, &definitions)?; if !then_block_str.is_empty() { body.push_str(&then_block_str); } else { @@ -2193,7 +2669,8 @@ impl<'a> Exporter<'a> { break; } } - let else_block = self.block(module, else_block, &pushed_indent, None)?; + let else_block = + self.block(module, else_block, &pushed_indent, &definitions)?; drop(pushed_indent); if !else_block.is_empty() { writeln!(body, "{indent}else:").unwrap(); @@ -2236,7 +2713,8 @@ impl<'a> Exporter<'a> { }; body.push_str(":\n"); let match_arm_indent = indent.push(); - let block = self.block(module, match_arm_block, &match_arm_indent, None)?; + let block = + self.block(module, match_arm_block, &match_arm_indent, &definitions)?; if !block.is_empty() { body.push_str(&block); } else { @@ -2274,26 +2752,18 @@ impl<'a> Exporter<'a> { instance, })) => { self.targeted_annotations(module_name, vec![], &annotations)?; - let name = self.module.ns.get(instance.name_id()); - let instantiated = instance.instantiated(); - self.add_module(instantiated); - let module_name = self.global_ns.get(instantiated.name_id()); - writeln!( - body, - "{indent}inst {name} of {module_name}{}", - FileInfo::new(instance.source_location()), - ) - .unwrap(); + writeln!(body, "{indent}{}", self.instance(instance)?).unwrap(); } } - definitions.write_and_clear(indent, &mut out); + definitions.write_out(indent, &mut out); out.push_str(&body); body.clear(); } Ok(out) } fn module(&mut self, module: Interned>) -> Result { - self.module = ModuleState::default(); + self.module = ModuleState::new(module); + let module_definitions = self.module.block_definitions.clone(); let indent = self.indent; let module_name = self.global_ns.get(module.name_id()); let mut body = String::new(); @@ -2362,12 +2832,10 @@ impl<'a> Exporter<'a> { "extmodule" } ModuleBody::Normal(NormalModuleBody { body: top_block }) => { - body.push_str(&self.block( - module, - top_block, - &module_indent, - Some(self.module.definitions.clone()), - )?); + let body_str = + self.block(module, top_block, &module_indent, &module_definitions)?; + module_definitions.write_out(indent, &mut body); + body.push_str(&body_str); "module" } }; @@ -2714,7 +3182,7 @@ fn export_impl( seen_modules: HashSet::default(), unwritten_modules: VecDeque::new(), global_ns, - module: ModuleState::default(), + module: ModuleState::new(top_module), type_state: TypeState::default(), circuit_name, annotations: vec![], diff --git a/crates/fayalite/src/formal.rs b/crates/fayalite/src/formal.rs index 17d3122..77ef808 100644 --- a/crates/fayalite/src/formal.rs +++ b/crates/fayalite/src/formal.rs @@ -1,11 +1,189 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ + expr::target::{GetTarget, Target}, int::BoolOrIntType, - intern::{Intern, Interned, Memoize}, + intern::{Intern, Interned}, + module::{NameId, NameIdOrGlobal, ScopedNameId}, prelude::*, }; -use std::sync::OnceLock; +use std::{fmt, sync::OnceLock}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum FormalInputKind { + FormalGlobalClock, + FormalReset, + AnyConst, + AnySeq, + AllConst, + AllSeq, +} + +impl FormalInputKind { + pub fn fixed_ty(self) -> Option { + 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 { + struct Cache { + formal_global_clock: crate::module::Id, + formal_reset: crate::module::Id, + } + static CACHE: OnceLock = 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 { + 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 { + macro_rules! impl_interned_name { + ($($variant:ident,)*) => { + match self { + $(Self::$variant => { + static CACHE: OnceLock> = 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); + +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 { + 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> { + Some(Target::from(*self).intern_sized()) + } +} #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum FormalKind { @@ -138,110 +316,76 @@ make_formal!( hdl_cover ); -pub trait MakeFormalExpr: Type {} - -impl MakeFormalExpr for T {} - #[hdl] pub fn formal_global_clock() -> Expr { - #[hdl_module(extern)] - fn formal_global_clock() { - #[hdl] - let clk: Clock = m.output(); - m.annotate_module(BlackBoxInlineAnnotation { - path: "fayalite_formal_global_clock.v".intern(), - text: r"module __fayalite_formal_global_clock(output clk); - (* gclk *) - reg clk; -endmodule -" - .intern(), - }); - m.verilog_name("__fayalite_formal_global_clock"); - } - #[hdl] - let formal_global_clock = instance(formal_global_clock()); - formal_global_clock.clk + static CACHE: OnceLock> = OnceLock::new(); + *CACHE.get_or_init(|| { + let kind = FormalInputKind::FormalGlobalClock; + Expr::from_canonical( + FormalInput::new( + kind, + NameId( + kind.interned_name(), + kind.fixed_id().expect("known to have a fixed Id"), + ), + Clock.into(), + kind.fixed_source_location() + .expect("known to have a fixed SourceLocation"), + ) + .to_expr(), + ) + }) } #[hdl] pub fn formal_reset() -> Expr { - #[hdl_module(extern)] - fn formal_reset() { - #[hdl] - let rst: SyncReset = m.output(); - m.annotate_module(BlackBoxInlineAnnotation { - path: "fayalite_formal_reset.v".intern(), - text: r"module __fayalite_formal_reset(output rst); - assign rst = $initstate; -endmodule -" - .intern(), - }); - m.verilog_name("__fayalite_formal_reset"); - } - static MOD: OnceLock>> = OnceLock::new(); - #[hdl] - let formal_reset = instance(*MOD.get_or_init(formal_reset)); - formal_reset.rst + static CACHE: OnceLock> = OnceLock::new(); + *CACHE.get_or_init(|| { + let kind = FormalInputKind::FormalReset; + Expr::from_canonical( + FormalInput::new( + kind, + NameId( + kind.interned_name(), + kind.fixed_id().expect("known to have a fixed Id"), + ), + SyncReset.into(), + kind.fixed_source_location() + .expect("known to have a fixed SourceLocation"), + ) + .to_expr(), + ) + }) } macro_rules! make_any_const_fn { - ($ident:ident, $verilog_attribute:literal) => { + ($ident:ident, $ident_with_loc:ident, $verilog_attribute:literal, $kind:ident) => { + #[track_caller] #[hdl] pub fn $ident(ty: T) -> Expr { - #[hdl_module(extern)] - pub(super) fn $ident(ty: T) { - #[hdl] - let out: T = m.output(ty); - let width = ty.width(); - let verilog_bitslice = if width == 1 { - String::new() - } else { - format!(" [{}:0]", width - 1) - }; - m.annotate_module(BlackBoxInlineAnnotation { - path: Intern::intern_owned(format!( - "fayalite_{}_{width}.v", - stringify!($ident), - )), - text: Intern::intern_owned(format!( - r"module __fayalite_{}_{width}(output{verilog_bitslice} out); - (* {} *) - reg{verilog_bitslice} out; -endmodule -", - stringify!($ident), - $verilog_attribute, - )), - }); - m.verilog_name(format!("__fayalite_{}_{width}", stringify!($ident))); - } - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - struct TheMemoize(T); - impl Memoize for TheMemoize { - type Input = (); - type InputOwned = (); - type Output = Option>>>; - fn inner(self, _input: &Self::Input) -> Self::Output { - if self.0.width() == 0 { - None - } else { - Some($ident(self.0)) - } - } - } - let Some(module) = TheMemoize(ty).get_owned(()) else { - return 0_hdl_u0.cast_bits_to(ty); - }; - #[hdl] - let $ident = instance(module); - $ident.out + $ident_with_loc(ty, SourceLocation::caller()) + } + #[track_caller] + #[hdl] + pub fn $ident_with_loc( + ty: T, + source_location: SourceLocation, + ) -> Expr { + let kind = FormalInputKind::$kind; + Expr::from_canonical( + FormalInput::new( + kind, + NameId(kind.interned_name(), crate::module::Id::new()), + ty.canonical(), + source_location, + ) + .to_expr(), + ) } }; } -make_any_const_fn!(any_const, "anyconst"); -make_any_const_fn!(any_seq, "anyseq"); -make_any_const_fn!(all_const, "allconst"); -make_any_const_fn!(all_seq, "allseq"); +make_any_const_fn!(any_const, any_const_with_loc, "anyconst", AnyConst); +make_any_const_fn!(any_seq, any_seq_with_loc, "anyseq", AnySeq); +make_any_const_fn!(all_const, all_const_with_loc, "allconst", AllConst); +make_any_const_fn!(all_seq, all_seq_with_loc, "allseq", AllSeq); diff --git a/crates/fayalite/src/int/uint_in_range.rs b/crates/fayalite/src/int/uint_in_range.rs index edf2e25..4292d08 100644 --- a/crates/fayalite/src/int/uint_in_range.rs +++ b/crates/fayalite/src/int/uint_in_range.rs @@ -177,6 +177,8 @@ impl CastToImpl for Bool { } impl HdlPartialEqImpl for UIntInRangeMaskType { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type { HdlPartialEqImpl<$UIntInRangeType> for $UIntInRangeType { + const TRY_STRUCTURAL_EQ: bool = true; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -657,6 +661,8 @@ macro_rules! define_uint_in_range_type { impl HdlPartialEqImpl> for $UIntInRangeType { + const TRY_STRUCTURAL_EQ: bool = false; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -676,6 +682,8 @@ macro_rules! define_uint_in_range_type { impl HdlPartialEqImpl<$UIntInRangeType> for UIntType { + const TRY_STRUCTURAL_EQ: bool = false; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, diff --git a/crates/fayalite/src/intern.rs b/crates/fayalite/src/intern.rs index b78aa59..89cc53d 100644 --- a/crates/fayalite/src/intern.rs +++ b/crates/fayalite/src/intern.rs @@ -682,27 +682,62 @@ impl, U: ?Sized> AsRef for Inter #[derive(Clone, Debug)] pub struct InternedSliceIter { - slice: Interned<[T]>, - index: std::ops::Range, + iter: std::iter::Cloned>, +} + +impl Default for InternedSliceIter { + fn default() -> Self { + Self { + iter: [].iter().cloned(), + } + } } impl Iterator for InternedSliceIter { type Item = T; fn next(&mut self) -> Option { - self.index.next().map(|index| self.slice[index].clone()) + self.iter.next() } fn size_hint(&self) -> (usize, Option) { - self.index.size_hint() + self.iter.size_hint() + } + + fn count(self) -> usize { + self.iter.count() + } + + fn last(mut self) -> Option { + self.next_back() + } + + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) } } impl DoubleEndedIterator for InternedSliceIter { fn next_back(&mut self) -> Option { - self.index - .next_back() - .map(|index| self.slice[index].clone()) + self.iter.next_back() + } + + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) } } @@ -716,8 +751,7 @@ impl IntoIterator for Interned<[T]> { fn into_iter(self) -> Self::IntoIter { InternedSliceIter { - index: 0..self.len(), - slice: self, + iter: Interned::into_inner(self).iter().cloned(), } } } diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 816a286..e899fd7 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -8,7 +8,7 @@ use crate::{ clock::{Clock, ClockDomain}, enum_::{Enum, EnumMatchVariantsIter, EnumType}, expr::{ - Expr, Flow, ToExpr, ValueType, + Expr, ExprEnum, Flow, ToExpr, ValueType, ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, @@ -20,6 +20,7 @@ use crate::{ int::{Bool, DynSize, Size}, intern::{Intern, Interned}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, + module::transform::visit::{Visit, Visitor}, platform::PlatformIOBuilder, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, @@ -726,7 +727,57 @@ impl fmt::Display for NameId { } #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct ScopedNameId(pub NameId, pub NameId); +pub enum NameIdOrGlobal { + Global, + NameId(NameId), +} + +impl NameIdOrGlobal { + pub fn name_id(self) -> Option { + 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("<>"), + Self::NameId(name_id) => fmt::Display::fmt(name_id, f), + } + } +} + +impl From for NameIdOrGlobal { + fn from(value: NameId) -> Self { + Self::NameId(value) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct ScopedNameId(pub NameIdOrGlobal, pub NameId); impl fmt::Debug for ScopedNameId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -804,7 +855,7 @@ impl Instance { self.containing_module_name_id().0 } pub fn containing_module_name_id(self) -> NameId { - self.scoped_name.0 + self.scoped_name.0.unwrap_name_id() } pub fn name(self) -> Interned { self.name_id().0 @@ -821,11 +872,13 @@ impl Instance { pub fn source_location(self) -> SourceLocation { self.source_location } + #[track_caller] pub fn new_unchecked( scoped_name: ScopedNameId, instantiated: Interned>, source_location: SourceLocation, ) -> Self { + scoped_name.0.assert_is_name_id(); Self { scoped_name, instantiated, @@ -1598,12 +1651,63 @@ impl TargetState { } } +struct VisibleExprsStack { + buf: Vec>, + len: usize, +} + +impl VisibleExprsStack { + fn top(&mut self) -> &mut HashSet { + &mut self.buf[self.len - 1] + } + fn slice(&self) -> &[HashSet] { + &self.buf[..self.len] + } + fn contains(&self, v: &ExprEnum) -> bool { + self.slice().iter().any(|i| i.contains(v)) + } + fn push_empty(&mut self) { + #[cold] + fn push_empty_cold(stack: &mut VisibleExprsStack) { + stack.buf.push(HashSet::default()); + assert_eq!(stack.buf.len(), stack.len) + } + self.len += 1; + if self.len > self.buf.len() { + push_empty_cold(self) + } + } + fn pop(&mut self) { + let Some(new_len) = self.len.checked_sub(1) else { + unreachable!("visible exprs stack underflow"); + }; + self.buf[new_len].clear(); + self.len = new_len; + } +} + +impl Default for VisibleExprsStack { + fn default() -> Self { + Self { + buf: Vec::new(), + len: 0, + } + } +} + struct AssertValidityState { module: Module, blocks: Vec, + visible_exprs: VisibleExprsStack, target_states: HashMap, TargetState>, } +enum GetTargetStatesError { + NotFound, + IsGlobal, + FoundSimIoForGlobal(crate::expr::ops::SimIoForGlobal), +} + impl AssertValidityState { fn make_block_index(&mut self, block: Block) -> usize { let retval = self.blocks.len(); @@ -1614,7 +1718,7 @@ impl AssertValidityState { &'a self, target: Target, process_target_state: &dyn Fn(&'a TargetState, bool), - ) -> Result<(), ()> { + ) -> Result<(), GetTargetStatesError> { let mut target = target.unwrap_transparent_types(); loop { break match target { @@ -1667,8 +1771,24 @@ impl AssertValidityState { }; } } - fn get_base_state(&self, target_base: Interned) -> Result<&TargetState, ()> { - self.target_states.get(&target_base).ok_or(()) + fn get_base_state( + &self, + target_base: Interned, + ) -> Result<&TargetState, GetTargetStatesError> { + match *target_base { + TargetBase::ModuleIO(_) + | TargetBase::MemPort(_) + | TargetBase::Reg(_) + | TargetBase::RegSync(_) + | TargetBase::RegAsync(_) + | TargetBase::Wire(_) + | TargetBase::Instance(_) => self + .target_states + .get(&target_base) + .ok_or(GetTargetStatesError::NotFound), + TargetBase::FormalInput(_) => Err(GetTargetStatesError::IsGlobal), + TargetBase::SimIoForGlobal(v) => Err(GetTargetStatesError::FoundSimIoForGlobal(v)), + } } #[track_caller] fn insert_new_base(&mut self, target_base: Interned, declared_in_block: usize) { @@ -1761,16 +1881,30 @@ impl AssertValidityState { let result = self.get_target_states(*target, &|target_state, exact_target_unknown| { Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown); }); - if result.is_err() { - if is_lhs { - panic!("at {source_location}: tried to connect to not-yet-defined item: {target}"); - } else { + match result { + Ok(()) => {} + Err(GetTargetStatesError::NotFound) => { + if is_lhs { + panic!( + "at {source_location}: tried to connect to not-yet-defined item: {target}" + ); + } else { + panic!( + "at {source_location}: tried to connect from not-yet-defined item: {target}" + ); + } + } + Err(GetTargetStatesError::IsGlobal) => { + // no error + } + Err(GetTargetStatesError::FoundSimIoForGlobal(v)) => { panic!( - "at {source_location}: tried to connect from not-yet-defined item: {target}" - ); + "at {source_location}: fayalite::expr::ops::SimIoForGlobal is not allowed in Modules: {v:?}" + ) } } } + #[track_caller] fn process_conditional_sub_blocks( &mut self, parent_block: usize, @@ -1784,17 +1918,40 @@ impl AssertValidityState { } } #[track_caller] + fn assert_expr_validity(&mut self, expr: Expr, source_location: SourceLocation) { + let mut visitor = AssertExprValidity { state: self }; + match visitor.visit_expr(&expr) { + Ok(()) => {} + Err(e) => match e { + InvalidExpr::ExprIsNotVisible(expr) => { + if let Some(target) = expr.target() { + panic!( + "at {source_location}: expression isn't visible here, it's defined:\n\ + at {}: {expr:?}", + target.base().source_location(), + ); + } else { + panic!("at {source_location}: expression isn't visible here: {expr:?}"); + } + } + }, + } + } + #[track_caller] fn assert_subtree_validity(&mut self, block: usize) { + self.visible_exprs.push_empty(); let module = self.module; if block == 0 { for module_io in &*module.module_io { self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block); + self.visible_exprs.top().insert(module_io.module_io.into()); } } let Block { memories, stmts } = self.blocks[block]; for m in memories { for port in m.ports() { self.insert_new_base(TargetBase::intern_sized(port.into()), block); + self.visible_exprs.top().insert(port.into()); } } for stmt in stmts { @@ -1808,44 +1965,104 @@ impl AssertValidityState { } = connect; self.set_connect_side_written(lhs, source_location, true, block); self.set_connect_side_written(rhs, source_location, false, block); + self.assert_expr_validity(lhs, source_location); + self.assert_expr_validity(rhs, source_location); + } + Stmt::Formal(formal) => { + let StmtFormal { + kind: _, + clk, + pred, + en, + text: _, + source_location, + } = formal; + self.assert_expr_validity(clk, source_location); + self.assert_expr_validity(pred, source_location); + self.assert_expr_validity(en, source_location); } - Stmt::Formal(_) => {} Stmt::If(if_stmt) => { - let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block)); + let StmtIf { + cond, + source_location, + blocks: sub_blocks, + } = if_stmt; + self.assert_expr_validity(cond, source_location); + let sub_blocks = sub_blocks.map(|block| self.make_block_index(block)); self.process_conditional_sub_blocks(block, sub_blocks) } Stmt::Match(match_stmt) => { match_stmt.assert_validity(); + let StmtMatch { + expr, + source_location, + blocks: sub_blocks, + } = match_stmt; + self.assert_expr_validity(expr, source_location); let sub_blocks = Vec::from_iter( - match_stmt - .blocks + sub_blocks .into_iter() .map(|block| self.make_block_index(block)), ); - self.process_conditional_sub_blocks(block, sub_blocks.iter().copied()) + self.visible_exprs.push_empty(); + let visible_exprs_top = self.visible_exprs.top(); + for variant_index in 0..expr.ty().variants().len() { + visible_exprs_top + .insert(::new_by_index(expr, variant_index).into()); + } + self.process_conditional_sub_blocks(block, sub_blocks.iter().copied()); + self.visible_exprs.pop(); } Stmt::Declaration(StmtDeclaration::Wire(StmtWire { annotations: _, wire, - })) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block), + })) => { + self.insert_new_base(TargetBase::intern_sized(wire.into()), block); + self.visible_exprs.top().insert(wire.into()); + } Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::RegSync(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations: _, instance, - })) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block), + })) => { + self.insert_new_base(TargetBase::intern_sized(instance.into()), block); + self.visible_exprs.top().insert(instance.into()); + } } } + self.visible_exprs.pop(); } #[track_caller] fn assert_validity(&mut self) { @@ -1874,6 +2091,143 @@ impl AssertValidityState { } } +struct AssertExprValidity<'a> { + state: &'a mut AssertValidityState, +} + +enum InvalidExpr { + ExprIsNotVisible(Expr), +} + +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 Module { /// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead #[track_caller] @@ -1894,7 +2248,7 @@ impl Module { clocks_for_past, simulation: Some(simulation), }) => { - let mut clocks_for_past_set = HashSet::default(); + let mut clocks_for_past_set = HashSet::::default(); *clocks_for_past = clocks_for_past .iter() .copied() @@ -1915,7 +2269,9 @@ impl Module { } 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 - let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io)); + let module_io_set = HashSet::>::from_iter( + module_io.iter().map(|v| v.module_io), + ); for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() { if !module_io_set.contains(&**sim_io) { panic!( @@ -1999,6 +2355,7 @@ impl Module { AssertValidityState { module: self.canonical(), blocks: vec![], + visible_exprs: VisibleExprsStack::default(), target_states: HashMap::with_capacity_and_hasher(64, Default::default()), } .assert_validity(); @@ -2104,7 +2461,7 @@ impl RegBuilder>, Option>, T> ty, } = self; ModuleBuilder::with(|module_builder| { - let scoped_name = ScopedNameId(module_builder.name, NameId(name, Id::new())); + let scoped_name = ScopedNameId(module_builder.name.into(), NameId(name, Id::new())); let reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init); let retval = reg.to_expr(); // convert before borrow_mut since ModuleBuilder could be reentered by T::canonical() @@ -2500,6 +2857,9 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { instance, } .into(), + TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => { + unreachable!("not a valid annotation target") + } }; ModuleBuilder::with(|m| { unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt()) @@ -2514,7 +2874,7 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { #[track_caller] pub fn wire_with_loc(name: &str, source_location: SourceLocation, ty: T) -> Expr { 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::::new_unchecked(scoped_name, source_location, ty); let retval = wire.to_expr(); let canonical_wire = wire.canonical(); @@ -2546,7 +2906,7 @@ fn incomplete_declaration( source_location: SourceLocation, ) -> Rc> { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete { name: scoped_name, source_location, @@ -2722,7 +3082,7 @@ pub fn instance_with_loc( source_location: SourceLocation, ) -> Expr { 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:: { scoped_name, instantiated, @@ -2761,7 +3121,7 @@ fn memory_impl( source_location: SourceLocation, ) -> MemBuilder { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type); let mut impl_ = m.impl_.borrow_mut(); let body = impl_.body.builder_normal_body(); @@ -2916,7 +3276,7 @@ impl ModuleIO { NameId(self.bundle_field.name, self.id) } pub fn scoped_name(&self) -> ScopedNameId { - ScopedNameId(self.containing_module_name, self.name_id()) + ScopedNameId(self.containing_module_name.into(), self.name_id()) } pub fn source_location(&self) -> SourceLocation { self.source_location @@ -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 for InstantiatedModuleOrGlobal { + fn from(value: InstantiatedModule) -> Self { + Self::InstantiatedModule(value) + } +} + +impl fmt::Debug for InstantiatedModuleOrGlobal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Global => f.write_str("Global"), + Self::InstantiatedModule(v) => v.fmt(f), + } + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct TargetInInstantiatedModule { - pub instantiated_module: InstantiatedModule, - pub target: Target, +pub struct TargetInInstantiatedModuleOrGlobal { + instantiated_module_or_global: InstantiatedModuleOrGlobal, + target: Target, +} + +impl TargetInInstantiatedModuleOrGlobal { + #[track_caller] + pub fn new(instantiated_module_or_global: InstantiatedModuleOrGlobal, target: Target) -> Self { + match ( + instantiated_module_or_global, + target.base().target_name().0.0, + ) { + (InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::Global) + | (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::NameId(_)) => { + Self { + instantiated_module_or_global, + target, + } + } + (InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::NameId(_)) + | (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::Global) => { + panic!( + "instantiated_module_or_global doesn't match target.base().target_name().0.0:\n\ + instantiated_module_or_global: {instantiated_module_or_global:?}\n\ + target: {target:?}" + ) + } + } + } + #[track_caller] + pub fn from_target( + instantiated_module: impl Into, + 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)] diff --git a/crates/fayalite/src/module/transform.rs b/crates/fayalite/src/module/transform.rs index 063a1a3..7eec4cf 100644 --- a/crates/fayalite/src/module/transform.rs +++ b/crates/fayalite/src/module/transform.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information pub mod deduce_resets; +pub mod deduce_structural_eq_flags; pub mod simplify_enums; pub mod simplify_memories; pub mod visit; diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index 4595e84..50a58c5 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -1208,6 +1208,7 @@ impl RunPass

for ExprEnum { Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) } ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1215,6 +1216,10 @@ impl RunPass

for ExprEnum { ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args), ExprEnum::RegAsync(expr) => reg_expr_run_pass(expr, pass_args), ExprEnum::MemPort(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::FormalInput(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } } } } @@ -1649,6 +1654,35 @@ impl RunPassExpr for ops::ToTraceAsString { } } +impl RunPassExpr for ops::StructuralEq { + type Args<'a> = [Expr; 2]; + + fn args<'a>(&'a self) -> Self::Args<'a> { + [self.lhs(), self.rhs()] + } + + fn source_location(&self) -> Option { + None + } + + fn union_parts( + &self, + _resets: Resets, + args_resets: Vec, + 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>, + ) -> Result { + Ok(Self::with_flags(new_args[0], new_args[1], self.flags())) + } +} + impl RunPassExpr for ModuleIO { type Args<'a> = [Expr; 0]; @@ -1932,6 +1966,7 @@ impl_run_pass_copy!([] SVAttributeAnnotation); impl_run_pass_copy!([] UInt); impl_run_pass_copy!([] usize); impl_run_pass_copy!([] FormalKind); +impl_run_pass_copy!([] crate::formal::FormalInput); impl_run_pass_copy!([] PhantomConst); macro_rules! impl_run_pass_for_struct { @@ -2248,6 +2283,12 @@ impl RunPass

for TargetBase { &TargetBase::RegAsync(v) => v.into(), TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)), TargetBase::Instance(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Instance)), + TargetBase::FormalInput(v) => { + return Ok(v.run_pass(pass_args)?.map(TargetBase::FormalInput)); + } + TargetBase::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } }; Ok(reg.run_pass(pass_args)?.map(|reg| match reg { AnyReg::Reg(reg) => TargetBase::Reg(reg), diff --git a/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs b/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs new file mode 100644 index 0000000..8bb6138 --- /dev/null +++ b/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs @@ -0,0 +1,1011 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{ + bundle::BundleType, + enum_::EnumType, + expr::{ + ExprEnum, ToLiteralBits, + ops::{ + ArrayIndex, FieldAccess, StructuralEq, StructuralEqFlags, TraceAsStringAsInner, + VariantAccess, + }, + target::TargetBase, + }, + intern::{Intern, Interned, Memoize}, + module::{ + ModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtInstance, StmtReg, StmtWire, + transform::visit::{Fold, Folder, Visit, Visitor}, + }, + prelude::*, + util::{ + HashMap, + bool_fixed_point_solver::{BoolFixedPointSolver, Constraint, Variable}, + indented_print::{PushIndent, indented_println}, + }, +}; +use bitvec::{order::Lsb0, view::BitView}; +use hashbrown::hash_map::Entry; +use std::{convert::Infallible, fmt}; + +fn has_enums_with_fields(ty: CanonicalType) -> 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(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => false, + CanonicalType::Array(ty) => { + if ty.is_empty() { + false + } else { + has_enums_with_fields(ty.element()) + } + } + CanonicalType::Enum(ty) => ty.variants().iter().any(|variant| variant.ty.is_some()), + CanonicalType::Bundle(ty) => ty + .fields() + .iter() + .any(|field| has_enums_with_fields(field.ty)), + CanonicalType::TraceAsString(ty) => has_enums_with_fields(ty.inner_ty()), + } + } + } + MyMemoize.get_owned(ty) +} + +fn is_padding_zeroed(ty: CanonicalType, bits: &BitSlice) -> bool { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize { + ty: CanonicalType, + } + impl Memoize for MyMemoize { + type Input = BitSlice; + type InputOwned = BitVec; + type Output = bool; + + fn inner(self, bits: &Self::Input) -> Self::Output { + assert_eq!(self.ty.bit_width(), bits.len()); + match self.ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => true, + CanonicalType::Array(ty) => { + if bits.is_empty() { + true + } else { + let element_ty = ty.element(); + bits.chunks(element_ty.bit_width()) + .all(|bits| is_padding_zeroed(element_ty, bits)) + } + } + CanonicalType::Enum(ty) => { + let mut discriminant = 0usize; + let discriminant_bit_width = ty.discriminant_bit_width(); + let (discriminant_bits, bits) = bits.split_at(discriminant_bit_width); + discriminant.view_bits_mut::()[..discriminant_bit_width] + .copy_from_bitslice(discriminant_bits); + if let Some(variant) = ty.variants().get(discriminant) + && let Some(variant_ty) = variant.ty + { + let (bits, padding) = bits.split_at(variant_ty.bit_width()); + !padding.any() && is_padding_zeroed(variant_ty, bits) + } else { + !bits.any() + } + } + CanonicalType::Bundle(ty) => { + ty.fields() + .iter() + .zip(&ty.field_offsets()) + .all(|(field, offset)| { + is_padding_zeroed( + field.ty, + &bits[offset.bit_width..][..field.ty.bit_width()], + ) + }) + } + CanonicalType::TraceAsString(ty) => is_padding_zeroed(ty.inner_ty(), bits), + } + } + } + MyMemoize { ty }.get(bits) +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: Variable, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ExprVariables { + NoEnumsWithFields, + HasEnumsWithFields(ExprVariablesHasEnumsWithFields), +} + +impl From for ExprVariables { + fn from(v: ExprVariablesHasEnumsWithFields) -> Self { + Self::HasEnumsWithFields(v) + } +} + +#[derive(Copy, Clone)] +enum ExprOrUnknown { + Expr(Expr), + Unknown(T), +} + +impl fmt::Debug for ExprOrUnknown { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Expr(expr) => expr.fmt(f), + Self::Unknown(ty) => f.debug_tuple("Unknown").field(ty).finish(), + } + } +} + +fn write_expr_path(expr: impl ToExpr, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write_expr_enum_path(&Expr::expr_enum(expr.to_expr()), f) +} + +fn write_expr_enum_path(expr: &ExprEnum, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_target_base( + target_base: impl Into, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{:?}", target_base.into().target_name()) + } + match expr { + ExprEnum::FieldAccess(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, ".{}", expr.field_name()) + } + ExprEnum::VariantAccess(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, ".<{}>", expr.variant_name()) + } + ExprEnum::ArrayIndex(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, "[{}]", expr.element_index()) + } + ExprEnum::DynArrayIndex(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, "[...]") + } + ExprEnum::ToTraceAsString(expr) => { + write_expr_path(expr.inner(), f)?; + write!(f, ".to_trace_as_string()") + } + ExprEnum::TraceAsStringAsInner(expr) => { + write_expr_path(expr.arg(), f)?; + write!(f, ".") + } + ExprEnum::ModuleIO(expr) => fmt_target_base(*expr, f), + ExprEnum::Instance(expr) => fmt_target_base(*expr, f), + ExprEnum::Wire(expr) => fmt_target_base(*expr, f), + ExprEnum::Reg(expr) => fmt_target_base(*expr, f), + ExprEnum::RegSync(expr) => fmt_target_base(*expr, f), + ExprEnum::RegAsync(expr) => fmt_target_base(*expr, f), + ExprEnum::MemPort(expr) => fmt_target_base(*expr, f), + ExprEnum::FormalInput(expr) => fmt_target_base(*expr, f), + + 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::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) + | ExprEnum::CastBitsTo(_) + | ExprEnum::StructuralEq(_) + | ExprEnum::SimIoForGlobal(_) => write!(f, "..."), + } +} + +impl fmt::Display for ExprOrUnknown { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::Expr(expr) => write_expr_path(expr, f), + Self::Unknown(_ty) => write!(f, "Unknown(...)"), + } + } +} + +impl From> for ExprOrUnknown { + fn from(expr: Expr) -> Self { + Self::Expr(expr) + } +} + +impl ExprOrUnknown { + fn ty(self) -> T { + match self { + Self::Expr(expr) => expr.ty(), + Self::Unknown(ty) => ty, + } + } + fn map( + self, + map_ty: impl FnOnce(T) -> U, + map_expr: impl FnOnce(Expr) -> Expr, + ) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(map_expr(expr)), + Self::Unknown(ty) => ExprOrUnknown::Unknown(map_ty(ty)), + } + } + fn from_canonical(v: ExprOrUnknown) -> Self { + match v { + ExprOrUnknown::Expr(expr) => Self::Expr(Expr::from_canonical(expr)), + ExprOrUnknown::Unknown(ty) => Self::Unknown(T::from_canonical(ty)), + } + } +} + +impl ExprOrUnknown { + fn field_at_index(self, field_index: usize) -> ExprOrUnknown { + self.map( + |ty| ty.fields()[field_index].ty, + |expr| FieldAccess::new_by_index(expr, field_index).to_expr(), + ) + } +} + +impl ExprOrUnknown { + fn variant_at_index(self, variant_index: usize) -> Option> { + match self { + Self::Expr(expr) => { + expr.ty().variants()[variant_index].ty?; + Some(ExprOrUnknown::Expr( + VariantAccess::new_by_index(expr, variant_index).to_expr(), + )) + } + Self::Unknown(ty) => Some(ExprOrUnknown::Unknown(ty.variants()[variant_index].ty?)), + } + } +} + +impl ExprOrUnknown { + fn element(self, element_index: usize) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(ArrayIndex::new(expr, element_index).to_expr()), + Self::Unknown(ty) => ExprOrUnknown::Unknown(ty.element()), + } + } +} + +impl ExprOrUnknown { + fn inner(self) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(TraceAsStringAsInner::new(expr).to_expr()), + Self::Unknown(ty) => ExprOrUnknown::Unknown(ty.inner_ty()), + } + } +} + +#[derive(Debug)] +struct State { + root_module: Interned>, + debug_trace: bool, + assume_padding_is_zeroed_solver: BoolFixedPointSolver, + assume_padding_is_zeroed_is_false: Variable, + expr_variables: HashMap, ExprVariables>, + modules_visited: HashMap>, bool>, + folded_exprs: HashMap, +} + +impl State { + fn new(root_module: Interned>, debug_trace: bool) -> Self { + let mut assume_padding_is_zeroed_solver = BoolFixedPointSolver::new(true); + let assume_padding_is_zeroed_is_false = assume_padding_is_zeroed_solver.new_variable(); + let mut retval = Self { + root_module, + debug_trace, + assume_padding_is_zeroed_solver, + assume_padding_is_zeroed_is_false, + expr_variables: HashMap::default(), + modules_visited: HashMap::default(), + folded_exprs: HashMap::default(), + }; + retval.assume_padding_is_zeroed_add_constraint(Constraint::MaximallyConstrained { + variable: assume_padding_is_zeroed_is_false, + }); + retval + } + fn assume_padding_is_zeroed_add_constraint(&mut self, constraint: Constraint) { + if self.debug_trace { + indented_println!("assume_padding_is_zeroed_add_constraint: {constraint:?}"); + } + self.assume_padding_is_zeroed_solver + .add_constraint(constraint); + } + fn visit_expr_or_unknown(&mut self, expr: ExprOrUnknown) -> ExprVariables { + match expr { + ExprOrUnknown::Expr(expr) => self.visit_canonical_expr(expr), + ExprOrUnknown::Unknown(ty) => { + if has_enums_with_fields(ty) { + ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: self.assume_padding_is_zeroed_is_false, + } + .into() + } else { + ExprVariables::NoEnumsWithFields + } + } + } + } + fn connect( + &mut self, + lhs: impl Into>, + rhs: impl Into>, + is_bidirectional: bool, + ) { + let lhs = lhs.into(); + let rhs = rhs.into(); + let _push_indent; + if self.debug_trace { + indented_println!("connect({lhs}, {rhs}, is_bidirectional={is_bidirectional:?}):"); + _push_indent = PushIndent::new(); + indented_println!("lhs: {lhs:?}"); + indented_println!("rhs: {rhs:?}"); + } + let lhs_ty = lhs.ty(); + let lhs_variables = self.visit_expr_or_unknown(lhs); + let rhs_variables = self.visit_expr_or_unknown(rhs); + let ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: lhs_assume_padding_is_zeroed, + } = match lhs_variables { + ExprVariables::NoEnumsWithFields => return, + ExprVariables::HasEnumsWithFields(v) => v, + }; + let ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: rhs_assume_padding_is_zeroed, + } = match rhs_variables { + ExprVariables::NoEnumsWithFields => unreachable!(), + ExprVariables::HasEnumsWithFields(v) => v, + }; + if is_bidirectional { + self.assume_padding_is_zeroed_add_constraint(Constraint::Equal { + dest: lhs_assume_padding_is_zeroed, + src: rhs_assume_padding_is_zeroed, + }); + } else { + self.assume_padding_is_zeroed_add_constraint(Constraint::And { + dest: lhs_assume_padding_is_zeroed, + src: rhs_assume_padding_is_zeroed, + }); + } + match lhs_ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => { + unreachable!("variables are always ExprVariables::NoEnumsWithFields") + } + CanonicalType::Array(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.len(), rhs.ty().len()); + assert!(lhs_ty.len() > 0); + // All array indexing operations are constrained to have equal variables so just arbitrarily use index 0 + self.connect(lhs.element(0), rhs.element(0), is_bidirectional); + } + CanonicalType::Enum(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.variants().len(), rhs.ty().variants().len()); + for variant_index in 0..lhs_ty.variants().len() { + let lhs_variant = lhs.variant_at_index(variant_index); + let rhs_variant = rhs.variant_at_index(variant_index); + assert_eq!(lhs_variant.is_some(), rhs_variant.is_some()); + if let Some(lhs_variant) = lhs_variant + && let Some(rhs_variant) = rhs_variant + { + self.connect(lhs_variant, rhs_variant, is_bidirectional); + } + } + } + CanonicalType::Bundle(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.fields().len(), rhs.ty().fields().len()); + for (field_index, (lhs_field, rhs_field)) in lhs_ty + .fields() + .into_iter() + .zip(rhs.ty().fields()) + .enumerate() + { + assert_eq!(lhs_field.flipped, rhs_field.flipped); + if lhs_field.flipped { + // flipped, so exchange lhs/rhs when recursively calling connect + self.connect( + rhs.field_at_index(field_index), + lhs.field_at_index(field_index), + is_bidirectional, + ); + } else { + self.connect( + lhs.field_at_index(field_index), + rhs.field_at_index(field_index), + is_bidirectional, + ); + } + } + } + CanonicalType::TraceAsString(_) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::from_canonical(rhs); + // FlagsTree treats TraceAsString transparently, so the returned flags don't need to be adjusted. + // this expression and the inner expression are unioned together + self.connect(lhs.inner(), rhs.inner(), is_bidirectional) + } + } + } + fn visit_canonical_expr(&mut self, expr: Expr) -> ExprVariables { + let _push_indent; + let expr_enum = Expr::expr_enum(expr); + let ty = expr.ty(); + let retval; + match self.expr_variables.entry(expr_enum) { + Entry::Occupied(entry) => return *entry.get(), + Entry::Vacant(entry) => { + if self.debug_trace { + indented_println!( + "visit_canonical_expr({}):", + fmt::from_fn(|f| write_expr_path(expr, f)), + ); + _push_indent = PushIndent::new(); + } + if has_enums_with_fields(ty) { + let assume_padding_is_zeroed = + self.assume_padding_is_zeroed_solver.new_variable(); + retval = ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed, + }; + if self.debug_trace { + indented_println!("{retval:?}"); + } + entry.insert(retval.into()); + let Ok(()) = expr_enum.default_visit(self); + } else { + let retval = ExprVariables::NoEnumsWithFields; + if self.debug_trace { + indented_println!("{retval:?}"); + } + entry.insert(retval); + let Ok(()) = expr_enum.default_visit(self); + return retval; + } + } + } + if let Ok(bits) = expr_enum.to_literal_bits() { + let ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed, + } = retval; + if !is_padding_zeroed(ty, &bits) { + self.assume_padding_is_zeroed_add_constraint(Constraint::MaximallyConstrained { + variable: assume_padding_is_zeroed, + }); + } + return retval.into(); + } + let handle_array_index = |this: &mut Self, base: Expr| { + match this.visit_canonical_expr(Expr::canonical(base)) { + ExprVariables::NoEnumsWithFields => unreachable!(), + ExprVariables::HasEnumsWithFields(ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: src, + }) => this.assume_padding_is_zeroed_add_constraint(Constraint::Equal { + dest: retval.assume_padding_is_zeroed, + src, + }), + } + if !base.ty().is_empty() { + this.connect(ArrayIndex::new(base, 0).to_expr(), expr, true); + } + }; + let handle_reg = |this: &mut Self, init: Option>| { + let init = match init { + Some(init) => ExprOrUnknown::Expr(init), + None => ExprOrUnknown::Unknown(ty), + }; + this.connect(ExprOrUnknown::Expr(expr), init, false); + }; + match *expr_enum { + ExprEnum::UIntLiteral(_) + | ExprEnum::SIntLiteral(_) + | ExprEnum::BoolLiteral(_) + | ExprEnum::PhantomConst(_) => unreachable!("has no enums with fields"), + ExprEnum::BundleLiteral(bundle_literal) => { + let expr = Expr::::from_canonical(expr); + for (field_index, field) in bundle_literal.ty().fields().into_iter().enumerate() { + assert!(!field.flipped); + let field_expr = FieldAccess::new_by_index(expr, field_index).to_expr(); + self.visit_canonical_expr(field_expr); + self.connect(field_expr, bundle_literal.field_values()[field_index], true); + } + } + ExprEnum::ArrayLiteral(array_literal) => { + let expr = Expr::::from_canonical(expr); + for element_index in 0..array_literal.ty().len() { + let element_expr = ArrayIndex::new(expr, element_index).to_expr(); + self.visit_canonical_expr(element_expr); + self.connect( + element_expr, + array_literal.element_values()[element_index], + false, + ); + } + } + ExprEnum::EnumLiteral(enum_literal) => { + let expr = Expr::::from_canonical(expr); + let variant_access = + VariantAccess::new_by_index(expr, enum_literal.variant_index()).to_expr(); + self.visit_canonical_expr(variant_access); + if let Some(variant_value) = enum_literal.variant_value() { + self.connect(variant_access, variant_value, true); + } + } + ExprEnum::Uninit(_) => self.connect(expr, ExprOrUnknown::Unknown(ty), false), + 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(field_access) => { + match self.visit_canonical_expr(Expr::canonical(field_access.base())) { + ExprVariables::NoEnumsWithFields => unreachable!(), + ExprVariables::HasEnumsWithFields(ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: dest, + }) => { + self.assume_padding_is_zeroed_add_constraint(Constraint::And { + dest, + src: retval.assume_padding_is_zeroed, + }); + } + } + } + ExprEnum::VariantAccess(variant_access) => { + match self.visit_canonical_expr(Expr::canonical(variant_access.base())) { + ExprVariables::NoEnumsWithFields => unreachable!(), + ExprVariables::HasEnumsWithFields(ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: dest, + }) => { + self.assume_padding_is_zeroed_add_constraint(Constraint::And { + dest, + src: retval.assume_padding_is_zeroed, + }); + } + } + } + ExprEnum::ArrayIndex(expr) => handle_array_index(self, expr.base()), + ExprEnum::DynArrayIndex(expr) => handle_array_index(self, expr.base()), + ExprEnum::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) => {} + ExprEnum::CastBitsTo(_) => self.connect(expr, ExprOrUnknown::Unknown(ty), false), + ExprEnum::ToTraceAsString(expr) => { + self.visit_canonical_expr(expr.inner()); + } + ExprEnum::TraceAsStringAsInner(expr) => { + match self.visit_canonical_expr(Expr::canonical(expr.arg())) { + ExprVariables::NoEnumsWithFields => unreachable!(), + ExprVariables::HasEnumsWithFields(ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: src, + }) => self.assume_padding_is_zeroed_add_constraint(Constraint::Equal { + dest: retval.assume_padding_is_zeroed, + src, + }), + }; + } + ExprEnum::StructuralEq(_) => {} + ExprEnum::ModuleIO(_) => {} + ExprEnum::Instance(instance) => { + let expr = Expr::::from_canonical(expr); + for (field_index, module_io) in + instance.instantiated().module_io().into_iter().enumerate() + { + let module_io = module_io.module_io.to_expr(); + let field_access = FieldAccess::new_by_index(expr, field_index).to_expr(); + self.connect(module_io, field_access, true); + } + } + ExprEnum::Wire(_) => {} + ExprEnum::Reg(reg) => handle_reg(self, reg.init()), + ExprEnum::RegSync(reg) => handle_reg(self, reg.init()), + ExprEnum::RegAsync(reg) => handle_reg(self, reg.init()), + ExprEnum::MemPort(_) => self.connect(expr, ExprOrUnknown::Unknown(ty), false), + ExprEnum::FormalInput(_) => self.connect(expr, ExprOrUnknown::Unknown(ty), false), + ExprEnum::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } + } + retval.into() + } +} + +impl Visitor for State { + type Error = Infallible; + + fn visit_expr_enum(&mut self, expr_enum: &ExprEnum) -> Result<(), Self::Error> { + self.visit_canonical_expr(expr_enum.to_expr()); + Ok(()) + } + + fn visit_stmt_declaration(&mut self, stmt: &StmtDeclaration) -> Result<(), Self::Error> { + match stmt { + StmtDeclaration::Wire(StmtWire { + annotations: _, + wire, + }) => self.visit_canonical_expr(wire.to_expr()), + StmtDeclaration::Reg(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::RegSync(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::RegAsync(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::Instance(StmtInstance { + annotations: _, + instance, + }) => self.visit_canonical_expr(Expr::canonical(instance.to_expr())), + }; + Ok(()) + } + + fn visit_stmt(&mut self, stmt: &Stmt) -> Result<(), Self::Error> { + match stmt { + &Stmt::Connect(StmtConnect { + lhs, + rhs, + source_location: _, + }) => { + self.connect(lhs, rhs, false); + } + Stmt::Formal(_) | Stmt::If(_) | Stmt::Match(_) => stmt.default_visit(self)?, + Stmt::Declaration(stmt) => self.visit_stmt_declaration(stmt)?, + } + Ok(()) + } + + fn visit_module(&mut self, module: &Module) -> Result<(), Self::Error> { + let module = module.canonical().intern_sized(); + let visited = self.modules_visited.entry(module).or_insert(false); + if std::mem::replace(visited, true) { + return Ok(()); + } + let _push_indent; + if self.debug_trace { + indented_println!("visit_module({})", module.name()); + _push_indent = PushIndent::new(); + } + let external = match module.body() { + ModuleBody::Normal(_) => false, + ModuleBody::Extern(_) => true, + }; + let is_root_module = self.root_module == module; + if external || is_root_module { + for module_io in module.module_io() { + let expr = module_io.module_io.to_expr(); + let mut connect_unknown = |is_lhs| { + if is_lhs { + self.connect(expr, ExprOrUnknown::Unknown(expr.ty()), false); + } else { + self.connect(ExprOrUnknown::Unknown(expr.ty()), expr, false); + } + }; + // all main/external module I/O can have non-zeroed padding + if external { + // outputs are unknown + connect_unknown(module_io.module_io.is_output()); + } + // note: the root module can be external, so we don't use `else if` here + if is_root_module { + // inputs are unknown + connect_unknown(module_io.module_io.is_input()); + } + } + } + module.default_visit(self) + } +} + +impl Folder for State { + type Error = Infallible; + fn fold_structural_eq(&mut self, v: StructuralEq) -> Result { + let mut input_flags = |expr: Expr| -> StructuralEqFlags { + match self.expr_variables[&Expr::expr_enum(expr)] { + ExprVariables::NoEnumsWithFields => StructuralEqFlags { + assume_padding_is_zeroed: true, + }, + ExprVariables::HasEnumsWithFields(ExprVariablesHasEnumsWithFields { + assume_padding_is_zeroed: assume_padding_is_zeroed_var, + }) => { + let assume_padding_is_zeroed = self + .assume_padding_is_zeroed_solver + .value(assume_padding_is_zeroed_var); + if self.debug_trace { + indented_println!( + "fold_structural_eq::input_flags({}): {assume_padding_is_zeroed_var} => {assume_padding_is_zeroed:?}", + fmt::from_fn(|f| write_expr_path(expr, f)), + ); + } + StructuralEqFlags { + assume_padding_is_zeroed, + } + } + } + }; + let lhs_flags = input_flags(v.lhs()); + let rhs_flags = input_flags(v.rhs()); + let inputs_assume_padding_is_zeroed = + lhs_flags.assume_padding_is_zeroed & rhs_flags.assume_padding_is_zeroed; + let new_lhs = v.lhs().fold(self)?; + let new_rhs = v.rhs().fold(self)?; + let StructuralEqFlags { + assume_padding_is_zeroed: orig_assume_padding_is_zeroed, + } = v.flags(); + Ok(StructuralEq::with_flags( + new_lhs, + new_rhs, + StructuralEqFlags { + assume_padding_is_zeroed: inputs_assume_padding_is_zeroed + | orig_assume_padding_is_zeroed, + }, + )) + } + fn fold_expr_enum(&mut self, v: ExprEnum) -> Result { + if let Some(&retval) = self.folded_exprs.get(&v) { + return Ok(retval); + } + let retval = v.default_fold(self)?; + self.folded_exprs.insert(v, retval); + Ok(retval) + } +} + +pub fn deduce_structural_eq_flags(module: Interned>) -> Interned> { + deduce_structural_eq_flags_with_debug_tracing(module, false) +} + +pub fn deduce_structural_eq_flags_with_debug_tracing( + module: Interned>, + debug_trace: bool, +) -> Interned> { + static CACHE: std::sync::Mutex< + Option>, Interned>>>, + > = std::sync::Mutex::new(None); + let cache = CACHE.lock().expect("not poisoned"); + if let Some(retval) = cache.as_ref().and_then(|cache| cache.get(&module)) { + return *retval; + } + drop(cache); + // the algorithm proceeds in three stages: + // 1. Visitor for State: build a BoolFixedPointSolver with all the variables and constraints to determine what flags should be + // 2. BoolFixedPointSolver solves for the variables + // 3. Folder for State: transforming the StructuralEq operations to have the deduced flags + let mut state = State::new(module, debug_trace); + if debug_trace { + indented_println!("deduce_structural_eq_flags_with_debug_tracing: start"); + } + let Ok(()) = module.visit(&mut state); + if debug_trace { + indented_println!( + "deduce_structural_eq_flags_with_debug_tracing: added variables and constraints" + ); + } + state.assume_padding_is_zeroed_solver.solve(); + if debug_trace { + indented_println!("deduce_structural_eq_flags_with_debug_tracing: solved"); + } + let Ok(retval) = module.fold(&mut state); + if debug_trace { + indented_println!( + "deduce_structural_eq_flags_with_debug_tracing: transformed all StructuralEq operations" + ); + } + CACHE + .lock() + .expect("not poisoned") + .get_or_insert_default() + .extend([(module, retval), (retval, retval)]); + retval +} diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index 5f136f2..6c137ca 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -1,28 +1,26 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - array::{Array, ArrayType}, - bundle::{Bundle, BundleField, BundleType}, - enum_::{Enum, EnumType, EnumVariant}, + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, expr::{ - CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType, - ops::{self, EnumLiteral}, + ExprEnum, + ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags}, }, - hdl, - int::UInt, intern::{Intern, InternSlice, Interned, Memoize}, - memory::{DynPortType, Mem, MemPort}, + memory::{DynPortType, MemPort}, module::{ - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, - transform::visit::{Fold, Folder}, + Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, + transform::{ + deduce_structural_eq_flags::deduce_structural_eq_flags, + visit::{Fold, Folder}, + }, }, - source_location::SourceLocation, - ty::{CanonicalType, TraceAsString, Type}, + prelude::*, util::HashMap, - wire::Wire, }; -use core::fmt; use serde::{Deserialize, Serialize}; +use std::fmt; #[derive(Debug)] pub enum SimplifyEnumsError { @@ -96,11 +94,13 @@ enum EnumTypeState { struct ModuleState { module_name: NameId, + expr_cache: HashMap, + source_location: SourceLocation, } impl ModuleState { fn gen_name(&mut self, name: &str) -> ScopedNameId { - ScopedNameId(self.module_name, NameId(name.intern(), Id::new())) + ScopedNameId(self.module_name.into(), NameId(name.intern(), Id::new())) } } @@ -109,6 +109,45 @@ struct State { replacement_mem_ports: HashMap, Wire>, kind: SimplifyEnumsKind, module_state_stack: Vec, + new_prefix_stmts_for_block: Vec, + new_suffix_stmts_for_block: Vec, +} + +struct BlockScope<'a> { + state: &'a mut State, + parent_new_prefix_stmts_for_block: Vec, + parent_new_suffix_stmts_for_block: Vec, +} + +impl<'a> BlockScope<'a> { + fn new( + state: &'a mut State, + new_prefix_stmts_for_block: Vec, + new_suffix_stmts_for_block: Vec, + ) -> 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 { @@ -548,6 +587,185 @@ impl State { | CanonicalType::DynSimOnly(_) => unreachable!(), } } + fn handle_enum_structural_eq( + &mut self, + unfolded_ty: Enum, + folded_lhs: Expr, + folded_rhs: Expr, + flags: StructuralEqFlags, + ) -> Result, 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::>::from_canonical(folded_lhs).tag), + Expr::canonical(Expr::>::from_canonical(folded_rhs).tag), + StructuralEqFlags { + assume_padding_is_zeroed: true, + }, + ) + .to_expr(), + EnumTypeState::TagUIntAndBody(_) => { + let lhs = Expr::>::from_canonical(folded_lhs).tag; + let rhs = Expr::>::from_canonical(folded_rhs).tag; + lhs.cmp_eq(rhs) + } + EnumTypeState::UInt(_) => { + let lhs_int_tag_expr = Expr::::from_canonical(folded_lhs) + [..unfolded_ty.discriminant_bit_width()]; + let rhs_int_tag_expr = Expr::::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, + folded_rhs: Expr, + flags: StructuralEqFlags, + ) -> Result, 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::::from_canonical(folded_lhs), + *Expr::::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( @@ -675,6 +893,8 @@ impl Folder for State { fn fold_module(&mut self, v: Module) -> Result, Self::Error> { self.module_state_stack.push(ModuleState { module_name: v.name_id(), + expr_cache: HashMap::default(), + source_location: v.source_location(), }); let retval = Fold::default_fold(v, self); self.module_state_stack.pop(); @@ -682,30 +902,51 @@ impl Folder for State { } fn fold_expr_enum(&mut self, op: ExprEnum) -> Result { - match op { + if let Some(folded_op) = self + .module_state_stack + .last() + .expect("known to be in module") + .expr_cache + .get(&op) + { + return Ok(*folded_op); + } + let folded_op = match op { ExprEnum::EnumLiteral(op) => { let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?; - Ok(*Expr::expr_enum(self.handle_enum_literal( + *Expr::expr_enum(self.handle_enum_literal( op.ty(), op.variant_index(), folded_variant_value, - )?)) + )?) } ExprEnum::VariantAccess(op) => { let folded_base_expr = Expr::canonical(op.base()).fold(self)?; - Ok(*Expr::expr_enum(self.handle_variant_access( + *Expr::expr_enum(self.handle_variant_access( op.base().ty(), folded_base_expr, op.variant_index(), - )?)) + )?) } - ExprEnum::MemPort(mem_port) => Ok( + ExprEnum::StructuralEq(op) => { + let ty = op.lhs().ty(); + assert_eq!(ty, op.rhs().ty()); + let folded_lhs = Expr::canonical(op.lhs()).fold(self)?; + let folded_rhs = Expr::canonical(op.rhs()).fold(self)?; + *Expr::expr_enum(self.handle_structural_eq( + ty, + folded_lhs, + folded_rhs, + op.flags(), + )?) + } + ExprEnum::MemPort(mem_port) => { if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) { ExprEnum::Wire(wire) } else { ExprEnum::MemPort(mem_port.fold(self)?) - }, - ), + } + } ExprEnum::UIntLiteral(_) | ExprEnum::SIntLiteral(_) | ExprEnum::BoolLiteral(_) @@ -813,16 +1054,26 @@ impl Folder for State { | ExprEnum::Wire(_) | ExprEnum::Reg(_) | ExprEnum::RegSync(_) - | ExprEnum::RegAsync(_) => op.default_fold(self), - } + | ExprEnum::RegAsync(_) + | ExprEnum::FormalInput(_) + | ExprEnum::SimIoForGlobal(_) => op.default_fold(self)?, + }; + self.module_state_stack + .last_mut() + .expect("known to be in module") + .expr_cache + .insert(op, folded_op); + Ok(folded_op) } fn fold_block(&mut self, block: Block) -> Result { + let block_scope = BlockScope::new(self, vec![], vec![]); + let this = &mut *block_scope.state; let mut memories = vec![]; let mut stmts = vec![]; for memory in block.memories { let old_element_ty = memory.array_type().element(); - let new_element_ty = memory.array_type().element().fold(self)?; + let new_element_ty = memory.array_type().element().fold(this)?; if new_element_ty != old_element_ty { let mut new_ports = vec![]; for port in memory.ports() { @@ -848,7 +1099,7 @@ impl Folder for State { continue; } let wire = Wire::new_unchecked( - self.module_state_stack + this.module_state_stack .last_mut() .unwrap() .gen_name(&format!( @@ -872,7 +1123,7 @@ impl Folder for State { Expr::canonical(wire.to_expr()), port.source_location(), ); - self.replacement_mem_ports.insert(port, wire.canonical()); + this.replacement_mem_ports.insert(port, wire.canonical()); } memories.push(Mem::new_unchecked( memory.scoped_name(), @@ -887,10 +1138,12 @@ impl Folder for State { memory.mem_annotations(), )); } else { - memories.push(memory.fold(self)?); + memories.push(memory.fold(this)?); } } - stmts.extend_from_slice(&block.stmts.fold(self)?); + stmts.extend_from_slice(&block.stmts.fold(this)?); + stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..)); + stmts.extend_from_slice(&this.new_suffix_stmts_for_block); Ok(Block { memories: Intern::intern_owned(memories), stmts: Intern::intern_owned(stmts), @@ -1012,10 +1265,13 @@ pub fn simplify_enums( module: Interned>, kind: SimplifyEnumsKind, ) -> Result>, SimplifyEnumsError> { + let module = deduce_structural_eq_flags(module); module.fold(&mut State { enum_types: HashMap::default(), replacement_mem_ports: HashMap::default(), kind, module_state_stack: vec![], + new_prefix_stmts_for_block: vec![], + new_suffix_stmts_for_block: vec![], }) } diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 7b4cd2a..17fd88c 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -18,13 +18,13 @@ use crate::{ TargetPathTraceAsStringInner, }, }, - formal::FormalKind, + formal::{FormalInput, FormalInputKind, FormalKind}, int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite}, module::{ AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId, + ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId, NameIdOrGlobal, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, }, @@ -482,4 +482,30 @@ impl, State: ?Sized + Visitor> Visit for &'_ mut } } +impl Visit for NameIdOrGlobal { + fn visit(&self, state: &mut State) -> Result<(), ::Error> { + state.visit_name_id_or_global(self) + } + + fn default_visit(&self, state: &mut State) -> Result<(), ::Error> { + match self { + Self::Global => Ok(()), + Self::NameId(name_id) => name_id.visit(state), + } + } +} + +impl Fold for NameIdOrGlobal { + fn fold(self, state: &mut State) -> Result::Error> { + state.fold_name_id_or_global(self) + } + + fn default_fold(self, state: &mut State) -> Result::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")); diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index ba85817..1552eab 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -384,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst { } impl HdlPartialEqImpl for PhantomConst { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( lhs: Self, diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 42038ca..69feeb5 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -16,8 +16,8 @@ pub use crate::{ ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat, }, formal::{ - MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, - hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, + all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert, + hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, hdl_cover_with_enable, }, hdl, hdl_module, @@ -37,7 +37,7 @@ pub use crate::{ value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType}, }, source_location::SourceLocation, - testing::{FormalMode, assert_formal}, + testing::{FormalMode, assert_formal, checked_vcd_output}, ty::{AsMask, CanonicalType, TraceAsString, Type}, util::{ConstUsize, GenericConstUsize}, wire::Wire, diff --git a/crates/fayalite/src/reg.rs b/crates/fayalite/src/reg.rs index 7f50655..2e4ab16 100644 --- a/crates/fayalite/src/reg.rs +++ b/crates/fayalite/src/reg.rs @@ -79,6 +79,7 @@ impl Reg { if let Some(init) = init { assert_eq!(ty, init.ty(), "register's type must match init type"); } + scoped_name.0.assert_is_name_id(); Self { name: scoped_name, source_location, @@ -94,7 +95,7 @@ impl Reg { self.containing_module_name_id().0 } pub fn containing_module_name_id(&self) -> NameId { - self.name.0 + self.name.0.unwrap_name_id() } pub fn name(&self) -> Interned { self.name_id().0 diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 1247fd8..3bd8466 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -6,26 +6,29 @@ use crate::{ bundle::{BundleField, BundleType}, expr::{ - Flow, + ExprEnum, Flow, + ops::SimIoForGlobal, target::{ - GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, - TargetPathTraceAsStringInner, + GetTarget, Target, TargetBase, TargetChild, TargetPathArrayElement, + TargetPathBundleField, TargetPathElement, TargetPathTraceAsStringInner, }, }, + formal::FormalInput, int::BoolOrIntType, intern::{ - Intern, InternSlice, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId, + Intern, InternSlice, Interned, InternedCompare, InternedSliceIter, Memoize, + PtrEqWithTypeId, SupportsPtrEqWithTypeId, }, module::{ - ModuleIO, + ModuleIO, StmtFormal, transform::visit::{Fold, Folder, Visit, Visitor}, }, prelude::*, reset::ResetType, sim::{ compiler::{ - Compiled, CompiledBundleField, CompiledExternModule, CompiledTypeLayoutBody, - CompiledValue, ExternModuleClockForPast, + Compiled, CompiledAssert, CompiledBundleField, CompiledExternModule, + CompiledTypeLayoutBody, CompiledValue, ExternModuleClockForPast, }, interpreter::{ BreakAction, BreakpointsSet, RunResult, SmallUInt, State, @@ -50,7 +53,7 @@ use std::{ any::Any, cell::{Cell, RefCell}, collections::{BTreeMap, BTreeSet}, - fmt, + fmt::{self, Write}, future::{Future, IntoFuture}, hash::Hash, mem, @@ -315,6 +318,14 @@ impl_trace_decl! { ty: CanonicalType, flow: Flow, }), + FormalInput(TraceFormalInput { + fn children(self) -> _ { + [*self.child].intern_slice() + } + name: Interned, + child: Interned, + formal_input: FormalInput, + }), Bundle(TraceBundle { fn children(self) -> _ { self.fields @@ -1288,9 +1299,14 @@ impl SimulationModuleState { #[track_caller] fn get_io( &self, - mut target: Target, - which_module: WhichModule, + target: &mut Interned, + which_module: WhichModule<'_>, ) -> CompiledValue { + match which_module { + WhichModule::Main { global_io } => *target = global_io.to_sim_io_target(*target), + WhichModule::Extern { .. } => {} + } + let mut target = **target; assert!( target.canonical_ty().is_passive(), "simulator read/write expression must have a passive type \ @@ -1317,9 +1333,9 @@ impl SimulationModuleState { }; } match which_module { - WhichModule::Main => panic!( + WhichModule::Main { .. } => panic!( "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!( "simulator read/write expression must be \ @@ -1329,18 +1345,18 @@ impl SimulationModuleState { } } #[track_caller] - fn is_reset_async(&self, io: Expr, which_module: WhichModule) -> bool { - let Some(target) = io.target() else { + fn is_reset_async(&self, io: Expr, which_module: WhichModule<'_>) -> bool { + let Some(mut target) = io.target() else { match which_module { - WhichModule::Main => panic!( - "can't read from an expression that's not a field/element of `Simulation::io()`" + WhichModule::Main { .. } => panic!( + "can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`" ), WhichModule::Extern { .. } => panic!( "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::SInt(_) | CanonicalType::Bool(_) @@ -1360,24 +1376,24 @@ impl SimulationModuleState { fn read_helper_current( &self, io: Expr, - which_module: WhichModule, + which_module: WhichModule<'_>, ) -> MaybeNeedsSettle> { - let Some(target) = io.target() else { + let Some(mut target) = io.target() else { match which_module { - WhichModule::Main => panic!( - "can't read from an expression that's not a field/element of `Simulation::io()`" + WhichModule::Main { .. } => panic!( + "can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`" ), WhichModule::Extern { .. } => panic!( "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() { Flow::Source => { if !self.uninitialized_ios.is_empty() { match which_module { - WhichModule::Main => { + WhichModule::Main { .. } => { panic!( "can't read from an output before initializing all inputs\nuninitialized_ios={:#?}", SortedSetDebug(&self.uninitialized_ios), @@ -1396,7 +1412,9 @@ impl SimulationModuleState { Flow::Sink => { if self.uninitialized_ios.contains_key(&*target) { 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 { .. } => { panic!("can't read from an uninitialized output"); } @@ -1412,7 +1430,7 @@ impl SimulationModuleState { &self, io: Expr, read_time: ReadTime, - which_module: WhichModule, + which_module: WhichModule<'_>, ) -> MaybeNeedsSettle> { match read_time { ReadTime::Current => self.read_helper_current(io, which_module), @@ -1438,22 +1456,22 @@ impl SimulationModuleState { fn write_helper( &mut self, io: Expr, - which_module: WhichModule, + which_module: WhichModule<'_>, ) -> CompiledValue { - let Some(target) = io.target() else { + let Some(mut target) = io.target() else { match which_module { - WhichModule::Main => panic!( - "can't write to an expression that's not a field/element of `Simulation::io()`" + WhichModule::Main { .. } => panic!( + "can't write to an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`" ), WhichModule::Extern { .. } => panic!( "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() { 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"), }, Flow::Sink => {} @@ -1573,9 +1591,9 @@ impl fmt::Debug for SimulationExternModuleState { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum WhichModule { - Main, +#[derive(Copy, Clone)] +enum WhichModule<'a> { + Main { global_io: &'a SimulationGlobalIo }, Extern { module_index: usize }, } @@ -1986,6 +2004,7 @@ impl SensitivitySet { struct SimulationImpl { state: interpreter::State, io: Expr, + global_io: SimulationGlobalIo, main_module: SimulationModuleState, extern_modules: Box<[SimulationExternModuleState]>, trace_decls: TraceModule, @@ -2005,6 +2024,7 @@ struct SimulationImpl { >, waiting_sensitivity_sets_by_address: HashMap<*const SensitivitySet, Rc>, trace_as_string_buf: String, + asserts: Interned<[CompiledAssert]>, } impl fmt::Debug for SimulationImpl { @@ -2082,6 +2102,7 @@ impl SimulationImpl { let Self { state, io: self_io, + global_io, main_module, extern_modules, trace_decls, @@ -2095,10 +2116,15 @@ impl SimulationImpl { waiting_sensitivity_sets_by_compiled_value, waiting_sensitivity_sets_by_address, trace_as_string_buf: _, + asserts, } = self; f.debug_struct("Simulation") .field("state", state) .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("extern_modules", extern_modules) .field("trace_decls", trace_decls) @@ -2118,6 +2144,7 @@ impl SimulationImpl { "waiting_sensitivity_sets_by_compiled_value", &DebugSensitivitySetsByCompiledValue(waiting_sensitivity_sets_by_compiled_value), ) + .field("asserts", asserts) .finish_non_exhaustive() } fn new(compiled: Compiled) -> Self { @@ -2160,22 +2187,29 @@ impl SimulationImpl { Self { state: State::new(compiled.insns), io: compiled.io.to_expr(), + global_io: SimulationGlobalIo::new(compiled.global_io), main_module: SimulationModuleState::new( compiled - .io - .ty() - .fields() - .into_iter() - .zip(compiled.base_module.module_io) - .map(|(BundleField { name, .. }, value)| { - ( - io_target.join( - TargetPathElement::from(TargetPathBundleField { name }) - .intern_sized(), - ), - value, - ) - }), + .global_io + .iter() + .map(|&(global_io, value)| (global_io.into(), value)) + .chain( + compiled + .io + .ty() + .fields() + .into_iter() + .zip(compiled.base_module.module_io) + .map(|(BundleField { name, .. }, value)| { + ( + io_target.join( + TargetPathElement::from(TargetPathBundleField { name }) + .intern_sized(), + ), + value, + ) + }), + ), &[], ), extern_modules, @@ -2202,6 +2236,7 @@ impl SimulationImpl { waiting_sensitivity_sets_by_compiled_value: HashMap::default(), waiting_sensitivity_sets_by_address: HashMap::default(), trace_as_string_buf: String::with_capacity(256), + asserts: compiled.asserts, } } fn write_traces( @@ -2729,6 +2764,50 @@ impl SimulationImpl { self.cancel_wake_after_change(&sensitivity_set); } } + #[track_caller] + #[cold] + fn handle_failed_asserts(&mut self, assert_failed_log: Vec) -> ! { + 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) { if let Some(Event { instant: _, @@ -2831,6 +2910,7 @@ impl SimulationImpl { } } this.write_traces_after_event(); + this.check_for_failed_asserts(); this.check_waiting_sensitivity_sets(); } else { event_queue = first_entry.into_event_queue_lock(); @@ -2852,18 +2932,23 @@ impl SimulationImpl { fn settle(this_ref: &Rc>) { 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 { - WhichModule::Main => &self.main_module, + WhichModule::Main { .. } => &self.main_module, 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 { - WhichModule::Main => &mut self.main_module, - WhichModule::Extern { module_index } => { - &mut self.extern_modules[module_index].module_state - } + WhichModule::Main { .. } => (&mut self.main_module, which_module), + WhichModule::Extern { module_index } => ( + &mut self.extern_modules[module_index].module_state, + which_module, + ), } } #[track_caller] @@ -2871,18 +2956,23 @@ impl SimulationImpl { &mut self, io: Expr, read_time: ReadTime, - which_module: WhichModule, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, ) -> MaybeNeedsSettle { + let which_module = which_module(&self.global_io); self.get_module(which_module) .read_helper(Expr::canonical(io), read_time, which_module) .map(|compiled_value| ReadBitFn { compiled_value }) .apply_no_settle(&mut self.state) } #[track_caller] - fn write_bit(&mut self, io: Expr, value: bool, which_module: WhichModule) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); + fn write_bit( + &mut self, + io: Expr, + 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); match compiled_value.range.len().as_single() { Some(TypeLenSingle::SmallSlot) => { @@ -2900,8 +2990,9 @@ impl SimulationImpl { &mut self, io: Expr, read_time: ReadTime, - which_module: WhichModule, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, ) -> MaybeNeedsSettle, I::Value> { + let which_module = which_module(&self.global_io); self.get_module(which_module) .read_helper(Expr::canonical(io), read_time, which_module) .map(|compiled_value| ReadBoolOrIntFn { compiled_value, io }) @@ -2912,11 +3003,10 @@ impl SimulationImpl { &mut self, io: Expr, value: I::Value, - which_module: WhichModule, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(Expr::canonical(io), which_module); + let (module, which_module) = self.get_module_mut_and_which_module(which_module); + let compiled_value = module.write_helper(Expr::canonical(io), which_module); self.event_queue.add_event_for_now(EventKind::State); let value: BigInt = value.into(); match compiled_value.range.len().as_single() { @@ -3148,7 +3238,12 @@ impl SimulationImpl { any_change.get() } #[track_caller] - fn is_reset_async(&self, io: Expr, which_module: WhichModule) -> bool { + fn is_reset_async( + &self, + io: Expr, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, + ) -> bool { + let which_module = which_module(&self.global_io); self.get_module(which_module) .is_reset_async(io, which_module) } @@ -3157,11 +3252,12 @@ impl SimulationImpl { &mut self, io: Expr, read_time: ReadTime, - which_module: WhichModule, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, ) -> ( CompiledValue, MaybeNeedsSettle>, ) { + let which_module = which_module(&self.global_io); let compiled_value = self .get_module(which_module) .read_helper(io, read_time, which_module); @@ -3189,11 +3285,10 @@ impl SimulationImpl { &mut self, io: Expr, value: &SimValue, - which_module: WhichModule, + which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>, ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); + 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); assert_eq!(io.ty(), value.ty()); Self::read_write_sim_value_helper( @@ -3370,6 +3465,318 @@ impl Drop for SimulationImpl { } } +#[derive(Clone)] +pub struct SimulationGlobalIo { + global_io: Interned<[(SimIoForGlobal, CompiledValue)]>, + global_io_map: Rc>, +} + +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)]>) -> 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> { + self.contains(global) + .then(|| SimIoForGlobal::new(global).to_expr()) + } + #[must_use] + pub fn expr_to_global(&self, expr: Expr) -> Option { + 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) -> Interned { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct FormalInputExprToSimIoExpr; + impl Memoize for FormalInputExprToSimIoExpr { + type Input = Interned; + type InputOwned = Interned; + type Output = Interned; + + 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); + type IntoIter = SimulationGlobalIoIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for &'_ SimulationGlobalIo { + type Item = (FormalInput, Expr); + type IntoIter = SimulationGlobalIoIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for &'_ mut SimulationGlobalIo { + type Item = (FormalInput, Expr); + 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), + ) -> $item_ty:ty + $global_io_to_item_block:block + } + ) => { + #[derive(Clone, Default)] + pub struct $SimulationGlobalIoIter { + global_io: InternedSliceIter<(SimIoForGlobal, CompiledValue)>, + } + + impl $SimulationGlobalIoIter { + fn $global_io_to_item( + $global_io_to_item_arg: (SimIoForGlobal, CompiledValue), + ) -> $item_ty + $global_io_to_item_block + } + + impl Iterator for $SimulationGlobalIoIter { + type Item = $item_ty; + + fn next(&mut self) -> Option { + self.global_io.next().map(Self::global_io_to_item) + } + + fn size_hint(&self) -> (usize, Option) { + self.global_io.size_hint() + } + + fn count(self) -> usize { + self.global_io.count() + } + + fn last(mut self) -> Option { + self.next_back() + } + + fn nth(&mut self, n: usize) -> Option { + self.global_io.nth(n).map(Self::global_io_to_item) + } + + fn fold(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.global_io.next_back().map(Self::global_io_to_item) + } + + fn nth_back(&mut self, n: usize) -> Option { + self.global_io.nth_back(n).map(Self::global_io_to_item) + } + + fn rfold(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), + ) -> (FormalInput, Expr) { + 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), + ) -> 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), + ) -> Expr { + 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 { sim_impl: Rc>, io: Expr, @@ -3444,14 +3851,15 @@ macro_rules! impl_simulation_methods { ( async_await = ($($async:tt, $await: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])? pub $($async)? fn read_bool_or_int(&mut $self, io: Expr) -> I::Value { - let retval = $self - .sim_impl - .borrow_mut() - .read_bool_or_int(io, ReadTime::Current, $which_module); + let retval = $self.sim_impl.borrow_mut().read_bool_or_int( + io, + ReadTime::Current, + |$global_io: &SimulationGlobalIo| $which_module, + ); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? @@ -3464,64 +3872,74 @@ macro_rules! impl_simulation_methods { $self.sim_impl.borrow_mut().write_bool_or_int( io, SimValue::into_value(value), - $which_module, + |$global_io: &SimulationGlobalIo| $which_module, ); } $(#[$track_caller])? pub $($async)? fn write_clock(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); + $self.sim_impl.borrow_mut().write_bit( + Expr::canonical(io), + value, + |$global_io: &SimulationGlobalIo| $which_module, + ); } $(#[$track_caller])? pub $($async)? fn read_clock(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); + let retval = $self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Current, + |$global_io: &SimulationGlobalIo| $which_module, + ); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? pub $($async)? fn write_bool(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); + $self.sim_impl.borrow_mut().write_bit( + Expr::canonical(io), + value, + |$global_io: &SimulationGlobalIo| $which_module, + ); } $(#[$track_caller])? pub $($async)? fn read_bool(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); + let retval = $self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Current, + |$global_io: &SimulationGlobalIo| $which_module, + ); $self.settle_if_needed(retval)$(.$await)? } $(#[$track_caller])? pub $($async)? fn write_reset(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); + $self.sim_impl.borrow_mut().write_bit( + Expr::canonical(io), + value, + |$global_io: &SimulationGlobalIo| $which_module, + ); } $(#[$track_caller])? pub $($async)? fn read_reset(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), ReadTime::Current, $which_module); + let retval = $self.sim_impl.borrow_mut().read_bit( + Expr::canonical(io), + ReadTime::Current, + |$global_io: &SimulationGlobalIo| $which_module, + ); $self.settle_if_needed(retval)$(.$await)? } #[track_caller] pub fn is_reset_async(&$self, io: Expr) -> bool { - $self - .sim_impl - .borrow_mut() - .is_reset_async(Expr::canonical(io), $which_module) + $self.sim_impl.borrow().is_reset_async( + Expr::canonical(io), + |$global_io: &SimulationGlobalIo| $which_module, + ) } $(#[$track_caller])? pub $($async)? fn read(&mut $self, io: Expr) -> SimValue { - let retval = $self - .sim_impl - .borrow_mut() - .read(Expr::canonical(io), ReadTime::Current, $which_module).1; + let retval = $self.sim_impl.borrow_mut().read( + Expr::canonical(io), + ReadTime::Current, + |$global_io: &SimulationGlobalIo| $which_module, + ).1; SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) } $(#[$track_caller])? @@ -3529,7 +3947,7 @@ macro_rules! impl_simulation_methods { $self.sim_impl.borrow_mut().write( Expr::canonical(io), &SimValue::into_canonical(value.into_sim_value_with_type(io.ty())), - $which_module, + |$global_io: &SimulationGlobalIo| $which_module, ); } }; @@ -3568,6 +3986,9 @@ impl Simulation { pub fn io(&self) -> Expr { self.io.to_expr() } + pub fn global_io(&self) -> SimulationGlobalIo { + self.sim_impl.borrow().global_io.clone() + } pub fn from_compiled(compiled: Compiled) -> Self { let sim_impl = SimulationImpl::new(compiled.canonical()); Self { @@ -3593,7 +4014,7 @@ impl Simulation { impl_simulation_methods!( async_await = (), track_caller = (#[track_caller]), - which_module = |self| WhichModule::Main, + which_module = |self, global_io| WhichModule::Main { global_io }, ); #[doc(hidden)] /// This is explicitly unstable and may be changed/removed at any time @@ -3662,7 +4083,7 @@ impl ExternModuleSimulationState { let (key, value) = self .sim_impl .borrow_mut() - .read(io, ReadTime::Current, which_module); + .read(io, ReadTime::Current, |_| which_module); let value = self.settle_if_needed(value).await; let key = Rc::new(key); 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( io, ReadTime::Past { clock_for_past }, - WhichModule::Extern { + |_| WhichModule::Extern { module_index: self.module_index, }, ); @@ -3950,7 +4371,7 @@ impl ExternModuleSimulationState { let retval = self.sim_impl.borrow_mut().read_bit( Expr::canonical(io), ReadTime::Past { clock_for_past }, - WhichModule::Extern { + |_| WhichModule::Extern { module_index: self.module_index, }, ); @@ -3966,7 +4387,7 @@ impl ExternModuleSimulationState { let retval = self.sim_impl.borrow_mut().read_bit( Expr::canonical(io), ReadTime::Past { clock_for_past }, - WhichModule::Extern { + |_| WhichModule::Extern { module_index: self.module_index, }, ); @@ -3986,7 +4407,7 @@ impl ExternModuleSimulationState { let retval = self.sim_impl.borrow_mut().read_bit( Expr::canonical(io), ReadTime::Past { clock_for_past }, - WhichModule::Extern { + |_| WhichModule::Extern { module_index: self.module_index, }, ); @@ -4009,7 +4430,7 @@ impl ExternModuleSimulationState { .read( Expr::canonical(io), ReadTime::Past { clock_for_past }, - WhichModule::Extern { + |_| WhichModule::Extern { module_index: self.module_index, }, ) @@ -4019,7 +4440,7 @@ impl ExternModuleSimulationState { impl_simulation_methods!( async_await = (async, await), track_caller = (), - which_module = |self| WhichModule::Extern { module_index: self.module_index }, + which_module = |self, _global_io| WhichModule::Extern { module_index: self.module_index }, ); } diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index 4d6d9bc..d82a540 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -7,30 +7,32 @@ use crate::{ bundle::{BundleField, BundleType}, enum_::{EnumType, EnumVariant}, expr::{ - ExprEnum, Flow, ValueType, ops, + ExprEnum, Flow, ValueType, + ops::{self, SimIoForGlobal}, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, }, + formal::FormalKind, int::BoolOrIntType, intern::{Intern, InternSlice, Interned, Memoize}, memory::PortKind, module::{ - AnnotatedModuleIO, Block, ExternModuleBody, Id, InstantiatedModule, ModuleBody, NameId, - NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, - StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, - transform::deduce_resets::deduce_resets, + AnnotatedModuleIO, Block, ExternModuleBody, Id, InstantiatedModule, + InstantiatedModuleOrGlobal, ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, + StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, + StmtWire, TargetInInstantiatedModuleOrGlobal, transform::deduce_resets::deduce_resets, }, prelude::*, reset::{ResetType, ResetTypeDispatch}, sim::{ ExternModuleSimulation, SimTrace, SimTraceKind, SimTraces, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, TraceEnumDiscriminant, TraceEnumWithFields, - TraceFieldlessEnum, TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, - TraceMemoryLocation, TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, - TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, - TraceWire, + TraceFieldlessEnum, TraceFormalInput, TraceInstance, TraceLocation, TraceMem, TraceMemPort, + TraceMemoryId, TraceMemoryLocation, TraceModule, TraceModuleIO, TracePhantomConst, + TraceReg, TraceSInt, TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, + TraceTraceAsString, TraceUInt, TraceWire, interpreter::{ self, Insn, InsnField, InsnFieldKind, InsnFieldType, InsnOrLabel, Insns, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, Label, PrefixLinesWrapper, SmallUInt, @@ -44,7 +46,7 @@ use crate::{ }, }, ty::{OpaqueSimValueSize, StaticType, TraceAsString}, - util::{HashMap, chain}, + util::{HashMap, HashSet, chain}, }; use bitvec::vec::BitVec; use num_bigint::BigInt; @@ -1751,6 +1753,19 @@ struct Memory { ports: Vec, } +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct CompiledAssert { + pub(crate) instantiated_module: Interned, + pub(crate) stmt_formal: StmtFormal, +} + +#[derive(Debug)] +struct Assert { + compiled_assert: CompiledAssert, + clk_triggered: StatePartIndex, + pred: StatePartIndex, +} + #[derive(Copy, Clone)] enum MakeTraceDeclTarget { Expr(Expr), @@ -1802,10 +1817,10 @@ pub struct Compiler { base_module: Interned>, modules: HashMap, extern_modules: Vec, - compiled_values: HashMap>, + compiled_values: HashMap>, compiled_exprs: HashMap, CompiledExpr>, compiled_exprs_to_values: HashMap, CompiledValue>, - decl_conditions: HashMap>, + decl_conditions: HashMap>, compiled_values_to_dyn_array_indexes: HashMap, StatePartIndex>, compiled_value_bool_dest_is_small_map: @@ -1818,6 +1833,10 @@ pub struct Compiler { traces: SimTraces>>, memories: Vec, dump_assignments_dot: Option>>, + global_io: Vec<(SimIoForGlobal, CompiledValue)>, + global_io_set: HashSet, + global_trace_decls: Vec, + asserts: Vec, } macro_rules! impl_compiler { @@ -1833,7 +1852,7 @@ macro_rules! impl_compiler { impl Compiler { fn make_trace_scalar_helper( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, target: MakeTraceDeclTarget, source_location: SourceLocation, empty_kind: impl FnOnce() -> SimTraceKind, @@ -1841,7 +1860,7 @@ macro_rules! impl_compiler { ) -> TraceLocation { match target { MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = self.compile_expr(instantiated_module_or_global, target); let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); if compiled_value.range.is_empty() { TraceLocation::Scalar(self.new_sim_trace(empty_kind())) @@ -1871,7 +1890,7 @@ macro_rules! impl_compiler { } fn make_trace_scalar( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, target: MakeTraceDeclTarget, name: Interned, source_location: SourceLocation, @@ -1880,7 +1899,7 @@ macro_rules! impl_compiler { match target.ty() { CanonicalType::UInt(ty) => TraceUInt { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -1895,7 +1914,7 @@ macro_rules! impl_compiler { .into(), CanonicalType::SInt(ty) => TraceSInt { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -1910,7 +1929,7 @@ macro_rules! impl_compiler { .into(), CanonicalType::Bool(_) => TraceBool { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -1927,7 +1946,7 @@ macro_rules! impl_compiler { assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); let location = match target { MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = self.compile_expr(instantiated_module_or_global, target); let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); let discriminant = self.compile_enum_discriminant( @@ -1964,7 +1983,7 @@ macro_rules! impl_compiler { CanonicalType::Bundle(_) => unreachable!(), CanonicalType::AsyncReset(_) => TraceAsyncReset { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -1978,7 +1997,7 @@ macro_rules! impl_compiler { .into(), CanonicalType::SyncReset(_) => TraceSyncReset { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -1993,7 +2012,7 @@ macro_rules! impl_compiler { CanonicalType::Reset(_) => unreachable!(), CanonicalType::Clock(_) => TraceClock { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -2007,7 +2026,7 @@ macro_rules! impl_compiler { .into(), CanonicalType::PhantomConst(ty) => TracePhantomConst { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || SimTraceKind::PhantomConst { ty }, @@ -2022,7 +2041,7 @@ macro_rules! impl_compiler { .into(), CanonicalType::DynSimOnly(ty) => TraceSimOnly { location: self.make_trace_scalar_helper( - instantiated_module, + instantiated_module_or_global, target, source_location, || unreachable!(), @@ -2038,7 +2057,7 @@ macro_rules! impl_compiler { CanonicalType::TraceAsString(ty) => { let location = match target { MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = self.compile_expr(instantiated_module_or_global, target); let CompiledValue { layout, range, write: _ } = self.compiled_expr_to_value(compiled_value, source_location).map_ty(Type::from_canonical); TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::TraceAsString { @@ -2314,6 +2333,10 @@ impl Compiler { traces: SimTraces(Vec::new()), memories: Vec::new(), dump_assignments_dot: None, + global_io: Vec::new(), + global_io_set: HashSet::default(), + global_trace_decls: Vec::new(), + asserts: Vec::new(), } } #[doc(hidden)] @@ -2333,16 +2356,17 @@ impl Compiler { } fn make_trace_decl_child( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: impl Into, target: MakeTraceDeclTarget, name: Interned, source_location: SourceLocation, ) -> TraceDecl { + let instantiated_module_or_global = instantiated_module_or_global.into(); match target.ty() { CanonicalType::Array(ty) => { let elements = Interned::from_iter((0..ty.len()).map(|index| { self.make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, match target { MakeTraceDeclTarget::Expr(target) => MakeTraceDeclTarget::Expr( Expr::::from_canonical(target)[index], @@ -2375,12 +2399,18 @@ impl Compiler { } CanonicalType::Enum(ty) => { if ty.variants().iter().all(|v| v.ty.is_none()) { - self.make_trace_scalar(instantiated_module, target, name, source_location) + self.make_trace_scalar( + instantiated_module_or_global, + target, + name, + source_location, + ) } else { let flow = target.flow(); let location = match target { MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = + self.compile_expr(instantiated_module_or_global, target); let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); let discriminant = self.compile_enum_discriminant( @@ -2419,7 +2449,7 @@ impl Compiler { |(variant_index, variant)| { variant.ty.map(|variant_ty| { self.make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, match target { MakeTraceDeclTarget::Expr(target) => { MakeTraceDeclTarget::Expr( @@ -2464,7 +2494,7 @@ impl Compiler { let fields = Interned::from_iter(ty.fields().iter().zip(ty.field_offsets()).map( |(field, field_offset)| { self.make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, match target { MakeTraceDeclTarget::Expr(target) => { MakeTraceDeclTarget::Expr(Expr::field( @@ -2514,22 +2544,23 @@ impl Compiler { | CanonicalType::DynSimOnly(_) | CanonicalType::PhantomConst(_) | CanonicalType::TraceAsString(_) => { - self.make_trace_scalar(instantiated_module, target, name, source_location) + self.make_trace_scalar(instantiated_module_or_global, target, name, source_location) } } } fn make_trace_decl( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: impl Into, target_base: TargetBase, ) -> TraceDecl { + let instantiated_module_or_global = instantiated_module_or_global.into(); let target = MakeTraceDeclTarget::Expr(target_base.to_expr()); match target_base { TargetBase::ModuleIO(module_io) => TraceModuleIO { name: module_io.name(), child: self .make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, module_io.name(), module_io.source_location(), @@ -2542,7 +2573,7 @@ impl Compiler { TargetBase::MemPort(mem_port) => { let name = Intern::intern_owned(mem_port.port_name().to_string()); let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, name, mem_port.source_location(), @@ -2560,7 +2591,7 @@ impl Compiler { name: reg.name(), child: self .make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, reg.name(), reg.source_location(), @@ -2573,7 +2604,7 @@ impl Compiler { name: reg.name(), child: self .make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, reg.name(), reg.source_location(), @@ -2586,7 +2617,7 @@ impl Compiler { name: reg.name(), child: self .make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, reg.name(), reg.source_location(), @@ -2599,7 +2630,7 @@ impl Compiler { name: wire.name(), child: self .make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, wire.name(), wire.source_location(), @@ -2610,13 +2641,18 @@ impl Compiler { .into(), TargetBase::Instance(instance) => { let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( - instantiated_module, + instantiated_module_or_global, target, instance.name(), instance.source_location(), ) else { unreachable!() }; + let InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module) = + instantiated_module_or_global + else { + unreachable!(); + }; let compiled_module = &self.modules[&InstantiatedModule::Child { parent: instantiated_module.intern(), instance: instance.intern(), @@ -2629,23 +2665,45 @@ impl Compiler { } .into() } + TargetBase::FormalInput(formal_input) => TraceFormalInput { + name: formal_input.name(), + child: self + .make_trace_decl_child( + instantiated_module_or_global, + target, + formal_input.name(), + formal_input.source_location(), + ) + .intern(), + formal_input, + } + .into(), + TargetBase::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } } } fn compile_value( &mut self, - target: TargetInInstantiatedModule, + target: TargetInInstantiatedModuleOrGlobal, ) -> CompiledValue { if let Some(&retval) = self.compiled_values.get(&target) { return retval; } - let retval = match target.target { + let mut new_global_io = None; + let retval = match target.target() { Target::Base(base) => { let unprefixed_layout = CompiledTypeLayout::get(base.canonical_ty()); - let layout = unprefixed_layout.with_prefixed_debug_names(&format!( - "{:?}.{:?}", - target.instantiated_module, - base.target_name() - )); + let layout = unprefixed_layout.with_prefixed_debug_names(&match target + .instantiated_module_or_global() + { + InstantiatedModuleOrGlobal::Global => { + format!("{:?}", base.target_name()) + } + InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module) => { + format!("{instantiated_module:?}.{:?}", base.target_name()) + } + }); let range = self.insns.allocate_variable(&layout.layout); let write = match *base { TargetBase::ModuleIO(_) @@ -2655,7 +2713,7 @@ impl Compiler { TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => { let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( "{:?}.{:?}$next", - target.instantiated_module, + target.instantiated_module_or_global(), base.target_name() )); Some(( @@ -2663,6 +2721,16 @@ impl Compiler { self.insns.allocate_variable(&write_layout.layout), )) } + TargetBase::FormalInput(formal_input) => { + if self.global_io_set.insert(SimIoForGlobal::new(formal_input)) { + new_global_io = + Some((formal_input, target.instantiated_module_or_global(), *base)); + } + None + } + TargetBase::SimIoForGlobal(_) => unreachable!( + "Module is known to not contain SimIoForGlobal from validation" + ), }; CompiledValue { range, @@ -2671,10 +2739,10 @@ impl Compiler { } } Target::Child(target_child) => { - let parent = self.compile_value(TargetInInstantiatedModule { - instantiated_module: target.instantiated_module, - target: *target_child.parent(), - }); + let parent = self.compile_value(TargetInInstantiatedModuleOrGlobal::new( + target.instantiated_module_or_global(), + *target_child.parent(), + )); match *target_child.path_element() { TargetPathElement::BundleField(TargetPathBundleField { name }) => { parent.map_ty(Bundle::from_canonical).field_by_name(name) @@ -2693,6 +2761,12 @@ impl Compiler { } }; self.compiled_values.insert(target, retval); + if let Some((new_global_io, instantiated_module_or_global, base)) = new_global_io { + let trace_decl = self.make_trace_decl(instantiated_module_or_global, base); + self.global_trace_decls.push(trace_decl); + self.global_io + .push((SimIoForGlobal::new(new_global_io), retval)); + } retval } fn add_assignment>( @@ -2707,18 +2781,20 @@ impl Compiler { } fn simple_big_expr_input( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, input: Expr, ) -> StatePartIndex { - let input = self.compile_expr(instantiated_module, input); - let input = - self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); + let input = self.compile_expr(instantiated_module_or_global, input); + let input = self.compiled_expr_to_value( + input, + instantiated_module_or_global.leaf_module_source_location(), + ); assert_eq!(input.range.len(), TypeLen::big_slot()); input.range.big_slots.start } fn compile_expr_helper( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, dest_ty: CanonicalType, make_insns: impl FnOnce(&mut Self, TypeIndexRange) -> Vec, ) -> CompiledValue { @@ -2733,24 +2809,24 @@ impl Compiler { self.add_assignment( Interned::default(), insns, - instantiated_module.leaf_module().source_location(), + instantiated_module_or_global.leaf_module_source_location(), ); retval } fn simple_nary_big_expr_helper( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, dest_ty: CanonicalType, make_insns: impl FnOnce(StatePartIndex) -> Vec, ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { + self.compile_expr_helper(instantiated_module_or_global, dest_ty, |_, dest| { assert_eq!(dest.len(), TypeLen::big_slot()); make_insns(dest.big_slots.start) }) } fn simple_nary_big_expr( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, dest_ty: CanonicalType, inputs: [Expr; N], make_insns: impl FnOnce( @@ -2758,8 +2834,9 @@ impl Compiler { [StatePartIndex; N], ) -> Vec, ) -> CompiledValue { - let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); - self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { + let inputs = + inputs.map(|input| self.simple_big_expr_input(instantiated_module_or_global, input)); + self.simple_nary_big_expr_helper(instantiated_module_or_global, dest_ty, |dest| { make_insns(dest, inputs) }) } @@ -2851,20 +2928,22 @@ impl Compiler { } fn compile_cast_scalar_to_bits( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, arg: Expr, cast_fn: impl FnOnce(Expr) -> Expr, ) -> CompiledValue { let arg = Expr::::from_canonical(arg); let retval = cast_fn(arg); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); + let retval = self.compile_expr(instantiated_module_or_global, Expr::canonical(retval)); + let retval = self.compiled_expr_to_value( + retval, + instantiated_module_or_global.leaf_module_source_location(), + ); retval.map_ty(UInt::from_canonical) } fn compile_cast_aggregate_to_bits( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, parts: impl IntoIterator>, ) -> CompiledValue { let retval = parts @@ -2872,22 +2951,26 @@ impl Compiler { .map(|part| part.cast_to_bits()) .reduce(|accumulator, part| accumulator | (part << accumulator.ty().width)) .unwrap_or_else(|| UInt[0].zero().to_expr()); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); + let retval = self.compile_expr(instantiated_module_or_global, Expr::canonical(retval)); + let retval = self.compiled_expr_to_value( + retval, + instantiated_module_or_global.leaf_module_source_location(), + ); retval.map_ty(UInt::from_canonical) } fn compile_cast_to_bits( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, expr: ops::CastToBits, ) -> CompiledValue { match expr.arg().ty() { CanonicalType::UInt(_) => { - self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) + self.compile_cast_scalar_to_bits(instantiated_module_or_global, expr.arg(), |arg| { + arg + }) } CanonicalType::SInt(ty) => self.compile_cast_scalar_to_bits( - instantiated_module, + instantiated_module_or_global, expr.arg(), |arg: Expr| arg.cast_to(ty.as_same_width_uint()), ), @@ -2896,33 +2979,33 @@ impl Compiler { | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) | CanonicalType::Clock(_) => self.compile_cast_scalar_to_bits( - instantiated_module, + instantiated_module_or_global, expr.arg(), |arg: Expr| arg.cast_to(UInt[1]), ), CanonicalType::Array(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, + instantiated_module_or_global, (0..ty.len()).map(|index| Expr::::from_canonical(expr.arg())[index]), ), CanonicalType::Enum(ty) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, UInt[ty.type_properties().bit_width].canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::Copy { dest, src }], ) .map_ty(UInt::from_canonical), CanonicalType::Bundle(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, + instantiated_module_or_global, ty.fields().iter().map(|field| { Expr::field(Expr::::from_canonical(expr.arg()), &field.name) }), ), CanonicalType::PhantomConst(_) | CanonicalType::DynSimOnly(_) => { - self.compile_cast_aggregate_to_bits(instantiated_module, []) + self.compile_cast_aggregate_to_bits(instantiated_module_or_global, []) } CanonicalType::TraceAsString(_) => self.compile_cast_to_bits( - instantiated_module, + instantiated_module_or_global, ops::CastToBits::new( ops::TraceAsStringAsInner::new(Expr::from_canonical(expr.arg())).to_expr(), ), @@ -2931,7 +3014,7 @@ impl Compiler { } fn compile_cast_bits_to_or_uninit( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, arg: Option>, ty: CanonicalType, ) -> CompiledValue { @@ -2960,7 +3043,7 @@ impl Compiler { } ty @ CanonicalType::Enum(_) => { return self.simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, ty, [Expr::canonical(arg.unwrap_or_else(|| { UInt::new_dyn(ty.bit_width()).zero().to_expr() @@ -3005,16 +3088,20 @@ impl Compiler { ), CanonicalType::PhantomConst(ty) => { if let Some(arg) = arg { - let _ = self.compile_expr(instantiated_module, Expr::canonical(arg)); + let _ = self.compile_expr(instantiated_module_or_global, Expr::canonical(arg)); } Expr::canonical(ty.to_expr()) } CanonicalType::DynSimOnly(ty) => { assert!(arg.is_none(), "can't cast bits to SimOnly"); - return self.compile_expr_helper(instantiated_module, ty.canonical(), |_, dest| { - assert_eq!(dest.len(), TypeLen::sim_only_slot()); - vec![] - }); + return self.compile_expr_helper( + instantiated_module_or_global, + ty.canonical(), + |_, dest| { + assert_eq!(dest.len(), TypeLen::sim_only_slot()); + vec![] + }, + ); } CanonicalType::TraceAsString(ty) => Expr::canonical( ops::ToTraceAsString::new( @@ -3027,24 +3114,27 @@ impl Compiler { .to_expr(), ), }; - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) + let retval = self.compile_expr(instantiated_module_or_global, Expr::canonical(retval)); + self.compiled_expr_to_value( + retval, + instantiated_module_or_global.leaf_module_source_location(), + ) } fn compile_aggregate_literal( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: InstantiatedModuleOrGlobal, dest_ty: CanonicalType, inputs: Interned<[Expr]>, ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |this, dest| { + self.compile_expr_helper(instantiated_module_or_global, dest_ty, |this, dest| { let mut insns = Vec::new(); let mut offset = TypeIndex::ZERO; for input in inputs { - let input = this.compile_expr(instantiated_module, input); + let input = this.compile_expr(instantiated_module_or_global, input); let input = this .compiled_expr_to_value( input, - instantiated_module.leaf_module().source_location(), + instantiated_module_or_global.leaf_module_source_location(), ) .range; insns.extend( @@ -3055,11 +3145,150 @@ impl Compiler { insns }) } + fn compile_structural_eq( + &mut self, + instantiated_module_or_global: InstantiatedModuleOrGlobal, + expr: ops::StructuralEq, + ) -> CompiledExpr { + if expr.flags().assume_padding_is_zeroed { + return self.compile_expr( + instantiated_module_or_global, + Expr::canonical(expr.lhs().cast_to_bits().cmp_eq(expr.rhs().cast_to_bits())), + ); + } + let source_location = instantiated_module_or_global.leaf_module_source_location(); + match expr.lhs().ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) => self.compile_expr( + instantiated_module_or_global, + Expr::canonical(expr.lhs().cast_to_bits().cmp_eq(expr.rhs().cast_to_bits())), + ), + CanonicalType::Array(_) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_expr( + instantiated_module_or_global, + Expr::canonical( + lhs.into_iter() + .zip(rhs) + .map(|(l, r)| { + ops::StructuralEq::with_flags(l, r, expr.flags()).to_expr() + }) + .reduce(|a, b| a & b) + .unwrap_or_else(|| true.to_expr()), + ), + ) + } + CanonicalType::Enum(ty) => { + let lhs = self.compile_expr(instantiated_module_or_global, expr.lhs()); + let lhs = self + .compiled_expr_to_value(lhs, source_location) + .map_ty(Enum::from_canonical); + let rhs = self.compile_expr(instantiated_module_or_global, expr.rhs()); + let rhs = self + .compiled_expr_to_value(rhs, source_location) + .map_ty(Enum::from_canonical); + let lhs_discriminant = self.compile_enum_discriminant(lhs, source_location); + let rhs_discriminant = self.compile_enum_discriminant(rhs, source_location); + let retval = self.simple_nary_big_expr( + instantiated_module_or_global, + Bool.canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: BigInt::ZERO.intern_sized(), + }] + }, + ); + for variant_index in 0..ty.variants().len() { + let variant_eq = self.compile_structural_eq( + instantiated_module_or_global, + ops::StructuralEq::with_flags( + ops::VariantAccess::new_by_index( + Expr::from_canonical(expr.lhs()), + variant_index, + ) + .to_expr(), + ops::VariantAccess::new_by_index( + Expr::from_canonical(expr.rhs()), + variant_index, + ) + .to_expr(), + expr.flags(), + ), + ); + let variant_eq = self.compiled_expr_to_value(variant_eq, source_location); + self.compile_simple_connect( + [ + Cond { + body: CondBody::MatchArm { + discriminant: lhs_discriminant, + variant_index, + }, + source_location, + }, + Cond { + body: CondBody::MatchArm { + discriminant: rhs_discriminant, + variant_index, + }, + source_location, + }, + ] + .intern_slice(), + retval.into(), + variant_eq, + source_location, + ); + } + retval.into() + } + CanonicalType::Bundle(ty) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_expr( + instantiated_module_or_global, + Expr::canonical( + (0..ty.fields().len()) + .map(|field_index| { + ops::StructuralEq::with_flags( + ops::FieldAccess::new_by_index(lhs, field_index).to_expr(), + ops::FieldAccess::new_by_index(rhs, field_index).to_expr(), + expr.flags(), + ) + .to_expr() + }) + .reduce(|a, b| a & b) + .unwrap_or_else(|| true.to_expr()), + ), + ) + } + CanonicalType::DynSimOnly(_) => { + unreachable!("StructuralEq is known to not have SimOnly in its inputs' types") + } + CanonicalType::TraceAsString(_) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_structural_eq( + instantiated_module_or_global, + ops::StructuralEq::with_flags(*lhs, *rhs, expr.flags()), + ) + } + } + } fn compile_expr( &mut self, - instantiated_module: InstantiatedModule, + instantiated_module_or_global: impl Into, expr: Expr, ) -> CompiledExpr { + let instantiated_module_or_global = instantiated_module_or_global.into(); if let Some(&retval) = self.compiled_exprs.get(&expr) { return retval; } @@ -3094,30 +3323,32 @@ impl Compiler { CanonicalType::DynSimOnly(_) => unreachable!(), CanonicalType::TraceAsString(_) => unreachable!(), }; - self.simple_nary_big_expr(instantiated_module, expr.ty(), [arg], |dest, [src]| match ( - src_signed, - dest_signed, - ) { - (false, false) | (true, true) => { - vec![Insn::Copy { dest, src }] - } - (false, true) => vec![Insn::CastToSInt { - dest, - src, - dest_width: 1, - }], - (true, false) => vec![Insn::CastToUInt { - dest, - src, - dest_width: 1, - }], - }) + self.simple_nary_big_expr( + instantiated_module_or_global, + expr.ty(), + [arg], + |dest, [src]| match (src_signed, dest_signed) { + (false, false) | (true, true) => { + vec![Insn::Copy { dest, src }] + } + (false, true) => vec![Insn::CastToSInt { + dest, + src, + dest_width: 1, + }], + (true, false) => vec![Insn::CastToUInt { + dest, + src, + dest_width: 1, + }], + }, + ) .into() }; let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) { ExprEnum::UIntLiteral(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [], |dest, []| { @@ -3130,7 +3361,7 @@ impl Compiler { .into(), ExprEnum::SIntLiteral(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [], |dest, []| { @@ -3142,21 +3373,38 @@ impl Compiler { ) .into(), ExprEnum::BoolLiteral(expr) => self - .simple_nary_big_expr(instantiated_module, Bool.canonical(), [], |dest, []| { - vec![Insn::Const { - dest, - value: BigInt::from(expr).intern_sized(), - }] - }) + .simple_nary_big_expr( + instantiated_module_or_global, + Bool.canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: BigInt::from(expr).intern_sized(), + }] + }, + ) .into(), ExprEnum::PhantomConst(_) => self - .compile_aggregate_literal(instantiated_module, expr.ty(), Interned::default()) + .compile_aggregate_literal( + instantiated_module_or_global, + expr.ty(), + Interned::default(), + ) .into(), ExprEnum::BundleLiteral(literal) => self - .compile_aggregate_literal(instantiated_module, expr.ty(), literal.field_values()) + .compile_aggregate_literal( + instantiated_module_or_global, + expr.ty(), + literal.field_values(), + ) .into(), ExprEnum::ArrayLiteral(literal) => self - .compile_aggregate_literal(instantiated_module, expr.ty(), literal.element_values()) + .compile_aggregate_literal( + instantiated_module_or_global, + expr.ty(), + literal.element_values(), + ) .into(), ExprEnum::EnumLiteral(expr) => { let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; @@ -3174,16 +3422,16 @@ impl Compiler { .to_expr() }; self.compile_expr( - instantiated_module, + instantiated_module_or_global, enum_bits.cast_bits_to(expr.ty().canonical()), ) } ExprEnum::Uninit(expr) => self - .compile_cast_bits_to_or_uninit(instantiated_module, None, expr.ty()) + .compile_cast_bits_to_or_uninit(instantiated_module_or_global, None, expr.ty()) .into(), ExprEnum::NotU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3197,7 +3445,7 @@ impl Compiler { .into(), ExprEnum::NotS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::NotS { dest, src }], @@ -3205,7 +3453,7 @@ impl Compiler { .into(), ExprEnum::NotB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3219,7 +3467,7 @@ impl Compiler { .into(), ExprEnum::Neg(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::Neg { dest, src }], @@ -3227,7 +3475,7 @@ impl Compiler { .into(), ExprEnum::BitAndU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -3235,7 +3483,7 @@ impl Compiler { .into(), ExprEnum::BitAndS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -3243,7 +3491,7 @@ impl Compiler { .into(), ExprEnum::BitAndB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -3251,7 +3499,7 @@ impl Compiler { .into(), ExprEnum::BitOrU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -3259,7 +3507,7 @@ impl Compiler { .into(), ExprEnum::BitOrS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -3267,7 +3515,7 @@ impl Compiler { .into(), ExprEnum::BitOrB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -3275,7 +3523,7 @@ impl Compiler { .into(), ExprEnum::BitXorU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -3283,7 +3531,7 @@ impl Compiler { .into(), ExprEnum::BitXorS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -3291,7 +3539,7 @@ impl Compiler { .into(), ExprEnum::BitXorB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -3299,7 +3547,7 @@ impl Compiler { .into(), ExprEnum::AddU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], @@ -3307,7 +3555,7 @@ impl Compiler { .into(), ExprEnum::AddS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], @@ -3315,7 +3563,7 @@ impl Compiler { .into(), ExprEnum::SubU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| { @@ -3330,7 +3578,7 @@ impl Compiler { .into(), ExprEnum::SubS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::SubS { dest, lhs, rhs }], @@ -3338,7 +3586,7 @@ impl Compiler { .into(), ExprEnum::MulU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], @@ -3346,7 +3594,7 @@ impl Compiler { .into(), ExprEnum::MulS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], @@ -3354,7 +3602,7 @@ impl Compiler { .into(), ExprEnum::DivU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], @@ -3362,7 +3610,7 @@ impl Compiler { .into(), ExprEnum::DivS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], @@ -3370,7 +3618,7 @@ impl Compiler { .into(), ExprEnum::RemU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], @@ -3378,7 +3626,7 @@ impl Compiler { .into(), ExprEnum::RemS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], @@ -3386,7 +3634,7 @@ impl Compiler { .into(), ExprEnum::DynShlU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], @@ -3394,7 +3642,7 @@ impl Compiler { .into(), ExprEnum::DynShlS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], @@ -3402,7 +3650,7 @@ impl Compiler { .into(), ExprEnum::DynShrU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], @@ -3410,7 +3658,7 @@ impl Compiler { .into(), ExprEnum::DynShrS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], @@ -3418,7 +3666,7 @@ impl Compiler { .into(), ExprEnum::FixedShlU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -3432,7 +3680,7 @@ impl Compiler { .into(), ExprEnum::FixedShlS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -3446,7 +3694,7 @@ impl Compiler { .into(), ExprEnum::FixedShrU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -3460,7 +3708,7 @@ impl Compiler { .into(), ExprEnum::FixedShrS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -3474,7 +3722,7 @@ impl Compiler { .into(), ExprEnum::CmpLtB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -3482,7 +3730,7 @@ impl Compiler { .into(), ExprEnum::CmpLeB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -3490,7 +3738,7 @@ impl Compiler { .into(), ExprEnum::CmpGtB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3499,7 +3747,7 @@ impl Compiler { .into(), ExprEnum::CmpGeB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3508,7 +3756,7 @@ impl Compiler { .into(), ExprEnum::CmpEqB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -3516,7 +3764,7 @@ impl Compiler { .into(), ExprEnum::CmpNeB(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -3524,7 +3772,7 @@ impl Compiler { .into(), ExprEnum::CmpLtU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -3532,7 +3780,7 @@ impl Compiler { .into(), ExprEnum::CmpLeU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -3540,7 +3788,7 @@ impl Compiler { .into(), ExprEnum::CmpGtU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3549,7 +3797,7 @@ impl Compiler { .into(), ExprEnum::CmpGeU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3558,7 +3806,7 @@ impl Compiler { .into(), ExprEnum::CmpEqU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -3566,7 +3814,7 @@ impl Compiler { .into(), ExprEnum::CmpNeU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -3574,7 +3822,7 @@ impl Compiler { .into(), ExprEnum::CmpLtS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -3582,7 +3830,7 @@ impl Compiler { .into(), ExprEnum::CmpLeS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -3590,7 +3838,7 @@ impl Compiler { .into(), ExprEnum::CmpGtS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3599,7 +3847,7 @@ impl Compiler { .into(), ExprEnum::CmpGeS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -3608,7 +3856,7 @@ impl Compiler { .into(), ExprEnum::CmpEqS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -3616,7 +3864,7 @@ impl Compiler { .into(), ExprEnum::CmpNeS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -3624,7 +3872,7 @@ impl Compiler { .into(), ExprEnum::CastUIntToUInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3638,7 +3886,7 @@ impl Compiler { .into(), ExprEnum::CastUIntToSInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3652,7 +3900,7 @@ impl Compiler { .into(), ExprEnum::CastSIntToUInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3666,7 +3914,7 @@ impl Compiler { .into(), ExprEnum::CastSIntToSInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3706,76 +3954,90 @@ impl Compiler { ExprEnum::CastClockToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::CastClockToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::FieldAccess(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .compile_expr(instantiated_module_or_global, Expr::canonical(expr.base())) .map_ty(Bundle::from_canonical) .field_by_index(expr.field_index()), ExprEnum::VariantAccess(variant_access) => { let start = variant_access.base().ty().discriminant_bit_width(); let len = expr.ty().bit_width(); self.compile_expr( - instantiated_module, + instantiated_module_or_global, variant_access.base().cast_to_bits()[start..start + len] .cast_bits_to(expr.ty()), ) } ExprEnum::ArrayIndex(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .compile_expr(instantiated_module_or_global, Expr::canonical(expr.base())) .map_ty(Array::from_canonical) .element(expr.element_index()), ExprEnum::DynArrayIndex(expr) => { - let element_index = - self.compile_expr(instantiated_module, Expr::canonical(expr.element_index())); + let element_index = self.compile_expr( + instantiated_module_or_global, + Expr::canonical(expr.element_index()), + ); let element_index = self.compiled_expr_to_value( element_index, - instantiated_module.leaf_module().source_location(), + instantiated_module_or_global.leaf_module_source_location(), ); let index_slot = self.compiled_value_to_dyn_array_index( element_index.map_ty(UInt::from_canonical), - instantiated_module.leaf_module().source_location(), + instantiated_module_or_global.leaf_module_source_location(), ); - self.compile_expr(instantiated_module, Expr::canonical(expr.base())) + self.compile_expr(instantiated_module_or_global, Expr::canonical(expr.base())) .map_ty(Array::from_canonical) .element_dyn(index_slot) } ExprEnum::ReduceBitAndU(expr) => if expr.arg().ty().width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + self.compile_expr( + instantiated_module_or_global, + Expr::canonical(true.to_expr()), + ) } else { self.compile_expr( - instantiated_module, + instantiated_module_or_global, Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))), ) } .into(), ExprEnum::ReduceBitAndS(expr) => if expr.arg().ty().width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + self.compile_expr( + instantiated_module_or_global, + Expr::canonical(true.to_expr()), + ) } else { self.compile_expr( - instantiated_module, + instantiated_module_or_global, Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))), ) } .into(), ExprEnum::ReduceBitOrU(expr) => if expr.arg().ty().width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + self.compile_expr( + instantiated_module_or_global, + Expr::canonical(false.to_expr()), + ) } else { self.compile_expr( - instantiated_module, + instantiated_module_or_global, Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))), ) } .into(), ExprEnum::ReduceBitOrS(expr) => if expr.arg().ty().width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + self.compile_expr( + instantiated_module_or_global, + Expr::canonical(false.to_expr()), + ) } else { self.compile_expr( - instantiated_module, + instantiated_module_or_global, Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))), ) } .into(), ExprEnum::ReduceBitXorU(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, UInt::<1>::TYPE.canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3789,7 +4051,7 @@ impl Compiler { .into(), ExprEnum::ReduceBitXorS(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, UInt::<1>::TYPE.canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -3803,7 +4065,7 @@ impl Compiler { .into(), ExprEnum::SliceUInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, UInt::new_dyn(expr.range().len()).canonical(), [Expr::canonical(expr.base())], |dest, [src]| { @@ -3818,7 +4080,7 @@ impl Compiler { .into(), ExprEnum::SliceSInt(expr) => self .simple_nary_big_expr( - instantiated_module, + instantiated_module_or_global, UInt::new_dyn(expr.range().len()).canonical(), [Expr::canonical(expr.base())], |dest, [src]| { @@ -3832,62 +4094,78 @@ impl Compiler { ) .into(), ExprEnum::CastToBits(expr) => self - .compile_cast_to_bits(instantiated_module, expr) + .compile_cast_to_bits(instantiated_module_or_global, expr) .map_ty(CanonicalType::UInt) .into(), ExprEnum::CastBitsTo(expr) => self - .compile_cast_bits_to_or_uninit(instantiated_module, Some(expr.arg()), expr.ty()) + .compile_cast_bits_to_or_uninit( + instantiated_module_or_global, + Some(expr.arg()), + expr.ty(), + ) .into(), ExprEnum::ToTraceAsString(expr) => self - .compile_expr(instantiated_module, expr.inner()) + .compile_expr(instantiated_module_or_global, expr.inner()) .wrap_in_trace_as_string(expr.ty()) .map_ty(|ty| ty.canonical()), ExprEnum::TraceAsStringAsInner(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.arg())) + .compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg())) .map_ty(TraceAsString::from_canonical) .inner(), + ExprEnum::StructuralEq(expr) => { + self.compile_structural_eq(instantiated_module_or_global, expr) + } ExprEnum::ModuleIO(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::Instance(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::Wire(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::Reg(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::RegSync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::RegAsync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), ExprEnum::MemPort(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) .into(), + ExprEnum::FormalInput(expr) => self + .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module_or_global, + expr.into(), + )) + .into(), + ExprEnum::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation"); + } }; self.compiled_exprs.insert(expr, retval); retval @@ -4013,10 +4291,11 @@ impl Compiler { let Some(target) = lhs.target() else { unreachable!("connect lhs must have target"); }; - let lhs_decl_conditions = self.decl_conditions[&TargetInInstantiatedModule { - instantiated_module: lhs_instantiated_module, - target: target.base().into(), - }]; + let lhs_decl_conditions = self.decl_conditions + [&TargetInInstantiatedModuleOrGlobal::from_target( + lhs_instantiated_module, + target.base().into(), + )]; let lhs = self.compile_expr(lhs_instantiated_module, lhs); let rhs = self.compile_expr(rhs_instantiated_module, rhs); let rhs = self.compiled_expr_to_value(rhs, source_location); @@ -4257,10 +4536,8 @@ impl Compiler { StmtDeclaration::RegAsync(v) => v.reg.into(), StmtDeclaration::Instance(v) => v.instance.into(), }; - let target = TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: target_base.into(), - }; + let target = + TargetInInstantiatedModuleOrGlobal::from_target(*parent_module, target_base.into()); self.decl_conditions.insert(target, conditions); let compiled_value = self.compile_value(target); match declaration { @@ -4324,6 +4601,56 @@ impl Compiler { } self.make_trace_decl(*parent_module, target_base) } + fn compile_stmt_formal( + &mut self, + stmt_formal: StmtFormal, + instantiated_module: Interned, + conditions: Interned<[Cond]>, + ) { + let StmtFormal { + kind, + clk, + pred, + en, + text: _, + source_location, + } = stmt_formal; + let clk = self.compile_expr(*instantiated_module, Expr::canonical(clk)); + let clk = self + .compiled_expr_to_value(clk, source_location) + .map_ty(Clock::from_canonical); + let clk = self.compile_clock(clk, source_location); + let pred = self.compile_expr(*instantiated_module, Expr::canonical(pred | !en)); + let pred = self.compiled_expr_to_value(pred, source_location); + let pred_layout = CompiledTypeLayout::get(Bool.canonical()); + let pred_wire = CompiledValue { + layout: pred_layout, + range: self.insns.allocate_variable(&pred_layout.layout), + write: None, + }; + let true_value = self.compile_expr(*instantiated_module, Expr::canonical(true.to_expr())); + let true_value = self.compiled_expr_to_value(true_value, source_location); + self.compile_simple_connect( + [].intern_slice(), + pred_wire.into(), + true_value, + source_location, + ); + self.compile_simple_connect(conditions, pred_wire.into(), pred, source_location); + match kind { + FormalKind::Assert | FormalKind::Assume => {} + FormalKind::Cover => todo!("simulating hdl_cover isn't implemented: {stmt_formal:?}"), + } + let pred = self.compiled_value_bool_dest_is_small(pred_wire, source_location); + self.asserts.push(Assert { + compiled_assert: CompiledAssert { + instantiated_module, + stmt_formal, + }, + clk_triggered: clk.clk_triggered, + pred, + }); + } fn allocate_delay_chain( &mut self, len: usize, @@ -4825,10 +5152,10 @@ impl Compiler { .iter() .map(|&port| { let target_base = TargetBase::MemPort(port); - let target = TargetInInstantiatedModule { + let target = TargetInInstantiatedModuleOrGlobal::from_target( instantiated_module, - target: target_base.into(), - }; + target_base.into(), + ); self.decl_conditions.insert(target, conditions); let TraceDecl::Scope(TraceScope::MemPort(trace_port)) = self.make_trace_decl(instantiated_module, target_base) @@ -5077,7 +5404,9 @@ impl Compiler { rhs, source_location, ), - Stmt::Formal(StmtFormal { .. }) => todo!("implement simulating formal statements"), + Stmt::Formal(stmt_formal) => { + self.compile_stmt_formal(stmt_formal, parent_module, conditions); + } Stmt::If(StmtIf { cond, source_location, @@ -5144,10 +5473,8 @@ impl Compiler { instantiated_module: InstantiatedModule, clock_for_past: Target, ) -> ExternModuleClockForPast { - let clock_for_past = TargetInInstantiatedModule { - instantiated_module, - target: clock_for_past, - }; + let clock_for_past = + TargetInInstantiatedModuleOrGlobal::from_target(instantiated_module, clock_for_past); let clock_for_past = self .compile_value(clock_for_past) .map_ty(Clock::from_canonical); @@ -5191,10 +5518,11 @@ impl Compiler { module_io, }| { let target_base = TargetBase::from(module_io); - let current = self.compile_value(TargetInInstantiatedModule { - instantiated_module, - target: target_base.into(), - }); + let current = + self.compile_value(TargetInInstantiatedModuleOrGlobal::from_target( + instantiated_module, + target_base.into(), + )); let unprefixed_layout = CompiledTypeLayout::get(module_io.ty()); let past_layout = unprefixed_layout.with_prefixed_debug_names(&format!( "{module_prefix}{:?}$past({trimmed_clock_for_past_debug_name})", @@ -5232,10 +5560,10 @@ impl Compiler { annotations: _, module_io, }| { - let target = TargetInInstantiatedModule { - instantiated_module: *module, - target: Target::from(module_io), - }; + let target = TargetInInstantiatedModuleOrGlobal::from_target( + *module, + Target::from(module_io), + ); self.decl_conditions.insert(target, Interned::default()); trace_decls.push(self.make_trace_decl(*module, module_io.into())); self.compile_value(target) @@ -5432,27 +5760,51 @@ impl Compiler { } } } + fn process_asserts(&mut self) { + for (assert_index, assert) in self.asserts.iter().enumerate() { + let Assert { + ref compiled_assert, + clk_triggered, + pred, + } = *assert; + self.insns.push( + Insn::Assert { + clk_triggered, + pred, + assert_index, + }, + compiled_assert.stmt_formal.source_location, + ); + } + } pub fn compile(mut self) -> Compiled { - let base_module = + let mut base_module = *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); self.process_assignments(); self.process_registers(); self.process_memories(); + self.process_asserts(); let clocks_triggered = self.process_clocks(); self.insns .push(Insn::Return, self.base_module.source_location()); + base_module.trace_decls.children = self + .global_trace_decls + .into_iter() + .chain(base_module.trace_decls.children) + .collect(); Compiled { insns: Insns::from(self.insns).intern_sized(), base_module, extern_modules: Intern::intern_owned(self.extern_modules), io: Instance::new_unchecked( ScopedNameId( - NameId("".intern(), Id::new()), + NameId("".intern(), Id::new()).into(), self.original_base_module.name_id(), ), self.original_base_module, self.original_base_module.source_location(), ), + global_io: Interned::from_iter(self.global_io), traces: SimTraces(Intern::intern_owned(self.traces.0)), trace_memories: Interned::from_iter(self.memories.iter().map( |&Memory { @@ -5463,6 +5815,11 @@ impl Compiler { }| (memory, trace), )), clocks_triggered, + asserts: Interned::from_iter( + self.asserts + .into_iter() + .map(|assert| assert.compiled_assert), + ), } } } @@ -5479,9 +5836,11 @@ pub struct Compiled { pub(crate) base_module: CompiledModule, pub(crate) extern_modules: Interned<[CompiledExternModule]>, pub(crate) io: Instance, + pub(crate) global_io: Interned<[(SimIoForGlobal, CompiledValue)]>, pub(crate) traces: SimTraces]>>, pub(crate) trace_memories: Interned<[(StatePartIndex, TraceMem)]>, pub(crate) clocks_triggered: Interned<[StatePartIndex]>, + pub(crate) asserts: Interned<[CompiledAssert]>, } impl Compiled { @@ -5494,18 +5853,22 @@ impl Compiled { base_module, extern_modules, io, + global_io, traces, trace_memories, clocks_triggered, + asserts, } = self; Compiled { insns, base_module, extern_modules, io: Instance::from_canonical(io.canonical()), + global_io, traces, trace_memories, clocks_triggered, + asserts, } } pub fn from_canonical(canonical: Compiled) -> Self { @@ -5514,18 +5877,22 @@ impl Compiled { base_module, extern_modules, io, + global_io, traces, trace_memories, clocks_triggered, + asserts, } = canonical; Self { insns, base_module, extern_modules, io: Instance::from_canonical(io.canonical()), + global_io, traces, trace_memories, clocks_triggered, + asserts, } } } diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 6b3eced..ee3331f 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -980,6 +980,7 @@ macro_rules! make_state { pub(crate) insns: Interned>, pub(crate) pc: usize, pub(crate) memory_write_log: Vec<(StatePartIndex, usize)>, + pub(crate) assert_failed_log: Vec, $(pub(crate) $state_plural_field: StatePart<$state_kind>,)* $(pub(crate) $type_plural_field: StatePart<$type_kind>,)* } @@ -990,6 +991,7 @@ macro_rules! make_state { insns: _, pc, memory_write_log, + assert_failed_log, $($state_plural_field,)* $($type_plural_field,)* } = self; @@ -997,6 +999,7 @@ macro_rules! make_state { .field("insns", &InsnsOfState(self)) .field("pc", pc) .field("memory_write_log", memory_write_log) + .field("assert_failed_log", assert_failed_log) $(.field(stringify!($state_plural_field), $state_plural_field))* $(.field(stringify!($type_plural_field), $type_plural_field))* .finish() @@ -1009,6 +1012,7 @@ macro_rules! make_state { insns, pc: 0, memory_write_log: Vec::with_capacity(32), + assert_failed_log: Vec::new(), $($state_plural_field: StatePart::new(&insns.state_layout.$state_plural_field.layout_data),)* $($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)* } @@ -1020,6 +1024,7 @@ macro_rules! make_state { pc: self.pc, orig_pc: &mut self.pc, memory_write_log: &mut self.memory_write_log, + assert_failed_log: &mut self.assert_failed_log, $($state_plural_field: self.$state_plural_field.borrow(),)* $($type_plural_field: self.$type_plural_field.borrow(),)* } @@ -1042,6 +1047,7 @@ macro_rules! make_state { pub(crate) orig_pc: &'a mut usize, pub(crate) pc: usize, pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex, usize)>, + pub(crate) assert_failed_log: &'a mut Vec, $(pub(crate) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)* $(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)* } @@ -1299,6 +1305,7 @@ impl State { insns: _, pc, memory_write_log: _, + assert_failed_log: _, memories: _, small_slots: _, big_slots: _, @@ -1338,6 +1345,10 @@ impl BorrowedState<'_> { self.memory_write_log.push(log_entry); } } + #[cold] + fn assert_failed(&mut self, assert_index: usize) { + self.assert_failed_log.push(assert_index); + } } fn bigint_pow2(width: usize) -> Interned { @@ -2105,6 +2116,19 @@ impl_insns! { state.log_memory_write(memory, addr); next!(); } + Assert { + #[kind = Input] + clk_triggered: StatePartIndex, + #[kind = Input] + pred: StatePartIndex, + #[kind = Immediate] + assert_index: usize, + } => { + if state.small_slots[clk_triggered] != 0 && state.small_slots[pred] == 0 { + state.assert_failed(assert_index); + } + next!(); + } Return => { break RunResult::Return(()); } diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index 24bc1ef..dd47633 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -1508,6 +1508,8 @@ impl ToSimValue for SimOnlyValue { } impl HdlPartialEqImpl for DynSimOnly { + const TRY_STRUCTURAL_EQ: bool = false; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -1527,6 +1529,8 @@ impl HdlPartialEqImpl for DynSimOnly { impl, R: SimOnlyValueTrait> HdlPartialEqImpl> for SimOnly { + const TRY_STRUCTURAL_EQ: bool = false; + #[track_caller] fn cmp_value_eq( _lhs: Self, diff --git a/crates/fayalite/src/sim/vcd.rs b/crates/fayalite/src/sim/vcd.rs index 09e7d66..17ad206 100644 --- a/crates/fayalite/src/sim/vcd.rs +++ b/crates/fayalite/src/sim/vcd.rs @@ -9,11 +9,11 @@ use crate::{ prelude::PhantomConst, sim::{ TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, - TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, - TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, - TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, TraceScalarId, - TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, TraceWire, - TraceWriter, TraceWriterDecls, + TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceFormalInput, + TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, + TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, + TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, + TraceWire, TraceWriter, TraceWriterDecls, time::{SimDuration, SimInstant}, value::DynSimOnlyValue, }, @@ -766,6 +766,7 @@ impl WriteTrace for TraceScope { Self::Wire(v) => v.write_trace(writer, arg), Self::Reg(v) => v.write_trace(writer, arg), Self::ModuleIO(v) => v.write_trace(writer, arg), + Self::FormalInput(v) => v.write_trace(writer, arg), Self::Bundle(v) => v.write_trace(writer, arg), Self::Array(v) => v.write_trace(writer, arg), Self::EnumWithFields(v) => v.write_trace(writer, arg), @@ -963,6 +964,27 @@ impl WriteTrace for TraceModuleIO { } } +impl WriteTrace for TraceFormalInput { + fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { + let ArgModuleBody { properties, scope } = arg.module_body(); + let Self { + name: _, + child, + formal_input: _, + } = self; + child.write_trace( + writer, + ArgInType { + source_var_type: "wire", + sink_var_type: "wire", + duplex_var_type: "wire", + properties, + scope: Some(scope), + }, + ) + } +} + impl WriteTrace for TraceBundle { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { let ArgInType { diff --git a/crates/fayalite/src/testing.rs b/crates/fayalite/src/testing.rs index bc7a0b1..cb9db9c 100644 --- a/crates/fayalite/src/testing.rs +++ b/crates/fayalite/src/testing.rs @@ -12,11 +12,13 @@ use crate::{ bundle::BundleType, firrtl::ExportOptions, module::Module, - util::HashMap, + sim::{Simulation, vcd::VcdWriterDecls}, + util::{HashMap, RcWriter}, }; use serde::{Deserialize, Serialize}; use std::{ fmt::{self, Write}, + panic::Location, path::{Path, PathBuf}, process::Command, sync::{Mutex, OnceLock}, @@ -222,3 +224,190 @@ pub fn assert_formal>, T: BundleType>( ) .expect("testing::assert_formal() failed"); } + +pub struct CheckedVcdOutput { + writer: Option, + expected_path: PathBuf, + expected_contents: Result, std::io::Error)>, + location: &'static Location<'static>, +} + +impl CheckedVcdOutput { + #[must_use] + #[track_caller] + pub fn new(sim: &mut Simulation, 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( + sim: &mut Simulation, + cargo_manifest_dir: &'static str, + path: &'static str, + ) -> Self { + Self::new(sim, Path::new(cargo_manifest_dir).join(path)) + } + pub fn with_vcd_output(&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( + &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; diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index ab69532..6505742 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -354,6 +354,39 @@ impl CanonicalType { } 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 { @@ -1309,16 +1342,49 @@ trait TraceAsStringTrait: fmt::Debug + 'static + Send + Sync + SupportsPtrEqWith fn can_substitute_type(&self, new_type: CanonicalType) -> bool; } -impl TraceAsStringTrait for T { +#[derive(Clone, PartialEq, Eq, Hash)] +struct TraceAsStringState { + ty: Interned, + canonical_ty: CanonicalType, +} + +impl TraceAsStringState { + fn new(ty: Interned) -> Interned { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize(PhantomData); + impl Memoize for MyMemoize { + type Input = Interned; + type InputOwned = Interned; + type Output = Interned>; + + fn inner(self, input: &Self::Input) -> Self::Output { + TraceAsStringState { + ty: *input, + canonical_ty: input.canonical(), + } + .intern_sized() + } + } + MyMemoize(PhantomData).get_owned(ty) + } +} + +impl fmt::Debug for TraceAsStringState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.ty.fmt(f) + } +} + +impl TraceAsStringTrait for TraceAsStringState { fn trace_fmt( &self, opaque: OpaqueSimValueSlice<'_>, f: &mut fmt::Formatter<'_>, ) -> 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 { - self.canonical().is_layout_equivalent(new_type) + self.canonical_ty.is_layout_equivalent(new_type) } } @@ -1374,7 +1440,7 @@ impl TraceAsString { Self { inner_ty: LazyInterned::Interned(inner_ty), trace_as_string: LazyInterned::Interned(Interned::cast_unchecked( - inner_ty, + TraceAsStringState::new(inner_ty), |v| -> &dyn TraceAsStringTrait { v }, )), } @@ -1548,7 +1614,10 @@ impl Default for TraceAsStringStaticTypeHelper { impl From> for Interned { fn from(_value: TraceAsStringStaticTypeHelper) -> 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( } impl, U: Type> HdlPartialEqImpl> for TraceAsString { + const TRY_STRUCTURAL_EQ: bool = >::TRY_STRUCTURAL_EQ; + #[track_caller] fn cmp_value_eq( lhs: Self, diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 6845d3c..0e6723e 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -16,8 +16,8 @@ pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher; #[cfg(not(feature = "unstable-test-hasher"))] pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder; -pub(crate) type HashMap = hashbrown::HashMap; -pub(crate) type HashSet = hashbrown::HashSet; +pub(crate) type HashMap = hashbrown::HashMap; +pub(crate) type HashSet = hashbrown::HashSet; #[doc(inline)] 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 mod bool_fixed_point_solver; +pub(crate) mod indented_print; pub mod job_server; +pub mod map_trait; pub mod prefix_sum; pub mod ready_valid; pub(crate) mod serde_by_id; +pub mod union_find_map; diff --git a/crates/fayalite/src/util/bool_fixed_point_solver.rs b/crates/fayalite/src/util/bool_fixed_point_solver.rs new file mode 100644 index 0000000..91119e9 --- /dev/null +++ b/crates/fayalite/src/util/bool_fixed_point_solver.rs @@ -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, + variables_value: Vec, + maximally_constrained: Vec, + unconstrained_variables_value: bool, + solved: bool, + and_constraints: BTreeSet, +} + +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![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 = (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> 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, Vec, [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, Vec, [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, Vec, Vec> { + 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, Vec, Vec> { + #[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, Vec, 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>( + 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 { + 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 { + 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 = 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); + } +} diff --git a/crates/fayalite/src/util/indented_print.rs b/crates/fayalite/src/util/indented_print.rs new file mode 100644 index 0000000..7243578 --- /dev/null +++ b/crates/fayalite/src/util/indented_print.rs @@ -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 = 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(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::($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::($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; diff --git a/crates/fayalite/src/util/map_trait.rs b/crates/fayalite/src/util/map_trait.rs new file mode 100644 index 0000000..6fc065c --- /dev/null +++ b/crates/fayalite/src/util/map_trait.rs @@ -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(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 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 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: 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 = Self> + 'a; + fn insert(self, v: ::Value) -> &'a mut ::Value; + fn insert_entry(self, v: ::Value) -> ::OccupiedEntry<'a>; + fn into_key(self) -> ::Key; + fn key(&self) -> &::Key; +} + +pub trait OccupiedEntry<'a>: Sized { + type Map: Map = Self> + 'a; + fn get(&self) -> &::Value; + fn get_mut(&mut self) -> &mut ::Value; + fn insert(&mut self, v: ::Value) -> ::Value; + fn into_mut(self) -> &'a mut ::Value; + fn key(&self) -> &::Key; + fn remove(self) -> ::Value; + fn remove_entry(self) -> (::Key, ::Value); +} + +pub trait Map: + Sized + + IntoIterator::Key, ::Value)> + + Extend<(::Key, ::Value)> + + FromIterator<(::Key, ::Value)> +{ + type Key; + type Value; + type IntoKeys: Iterator; + type IntoValues: Iterator; + type Iter<'a>: Iterator + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type IterMut<'a>: Iterator + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type Keys<'a>: Iterator + where + Self: 'a, + Self::Key: 'a; + type Values<'a>: Iterator + where + Self: 'a, + Self::Value: 'a; + type ValuesMut<'a>: Iterator + 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; + 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 bool>(&mut self, f: F); + fn values(&self) -> Self::Values<'_>; + fn values_mut(&mut self) -> Self::ValuesMut<'_>; +} + +pub trait MapGet: 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; + 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 Map for HashMap { + type Key = K; + type Value = V; + type IntoKeys = hash_map::IntoKeys; + type IntoValues = hash_map::IntoValues; + 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.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 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> MapGet + for HashMap + { + 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.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; + fn insert(self, v: ::Value) -> &'a mut ::Value { + self.insert(v) + } + fn insert_entry( + self, + v: ::Value, + ) -> ::OccupiedEntry<'a> { + self.insert_entry(v) + } + fn into_key(self) -> ::Key { + self.into_key() + } + fn key(&self) -> &::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; + fn get(&self) -> &::Value { + self.get() + } + fn get_mut(&mut self) -> &mut ::Value { + self.get_mut() + } + fn insert(&mut self, v: ::Value) -> ::Value { + self.insert(v) + } + fn into_mut(self) -> &'a mut ::Value { + self.into_mut() + } + fn key(&self) -> &::Key { + self.key() + } + fn remove(self) -> ::Value { + self.remove() + } + fn remove_entry(self) -> (::Key, ::Value) { + self.remove_entry() + } + } +} + +mod btree_map { + use super::*; + use std::collections::{BTreeMap, btree_map}; + + impl Map for BTreeMap { + type Key = K; + type Value = V; + type IntoKeys = btree_map::IntoKeys; + type IntoValues = btree_map::IntoValues; + 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.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 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, V, Q: ?Sized + Ord> MapGet for BTreeMap { + 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.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; + fn insert(self, v: ::Value) -> &'a mut ::Value { + self.insert(v) + } + fn insert_entry( + self, + v: ::Value, + ) -> ::OccupiedEntry<'a> { + self.insert_entry(v) + } + fn into_key(self) -> ::Key { + self.into_key() + } + fn key(&self) -> &::Key { + self.key() + } + } + + impl<'a, K: Ord, V> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> { + type Map = BTreeMap; + fn get(&self) -> &::Value { + self.get() + } + fn get_mut(&mut self) -> &mut ::Value { + self.get_mut() + } + fn insert(&mut self, v: ::Value) -> ::Value { + self.insert(v) + } + fn into_mut(self) -> &'a mut ::Value { + self.into_mut() + } + fn key(&self) -> &::Key { + self.key() + } + fn remove(self) -> ::Value { + self.remove() + } + fn remove_entry(self) -> (::Key, ::Value) { + self.remove_entry() + } + } +} diff --git a/crates/fayalite/src/util/ready_valid.rs b/crates/fayalite/src/util/ready_valid.rs index a15b837..66f0aea 100644 --- a/crates/fayalite/src/util/ready_valid.rs +++ b/crates/fayalite/src/util/ready_valid.rs @@ -241,15 +241,13 @@ mod tests { /// happens to be in phase with the offending input or output). #[hdl_module] fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) { - #[hdl] - let clk: Clock = m.input(); #[hdl] let cd = wire(); connect( cd, #[hdl] ClockDomain { - clk, + clk: formal_global_clock(), rst: formal_reset().to_reset(), }, ); @@ -280,7 +278,7 @@ mod tests { #[hdl] let index_to_check = wire(index_ty); connect(index_to_check, any_const(index_ty)); - hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), ""); + hdl_assume(cd.clk, index_to_check.cmp_lt(capacity.get()), ""); // instantiate and connect the queue #[hdl] @@ -300,13 +298,13 @@ mod tests { let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero()); #[hdl] if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) { - hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), ""); + hdl_assert(cd.clk, expected_count_reg.cmp_ne(capacity.get()), ""); connect_any(expected_count_reg, expected_count_reg + 1u8); } else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) { - hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), ""); + hdl_assert(cd.clk, expected_count_reg.cmp_ne(count_ty.zero()), ""); connect_any(expected_count_reg, expected_count_reg - 1u8); } - hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), ""); + hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), ""); // keep an independent write index into the FIFO's circular buffer #[hdl] @@ -374,7 +372,7 @@ mod tests { match inp_firing_data { // ... and we are not receiving data, then we must not // transmit any data. - HdlNone => hdl_assert(clk, HdlOption::is_none(out_firing_data), ""), + HdlNone => hdl_assert(cd.clk, HdlOption::is_none(out_firing_data), ""), // If we are indeed receiving some data... HdlSome(data_in) => { #[hdl] @@ -382,7 +380,9 @@ mod tests { // ... and transmitting at the same time, we // must be transmitting the input data itself, // since the holding register is empty. - HdlSome(data_out) => hdl_assert(clk, data_out.cmp_eq(data_in), ""), + HdlSome(data_out) => { + hdl_assert(cd.clk, data_out.cmp_eq(data_in), "") + } // If we are receiving, but not transmitting, // store the received data in the holding // register. @@ -397,11 +397,11 @@ mod tests { match out_firing_data { // ... and we are not transmitting it, we cannot // receive any more data. - HdlNone => hdl_assert(clk, HdlOption::is_none(inp_firing_data), ""), + HdlNone => hdl_assert(cd.clk, HdlOption::is_none(inp_firing_data), ""), // If we are transmitting a previously stored value... HdlSome(data_out) => { // ... it must be the same data we stored earlier. - hdl_assert(clk, data_out.cmp_eq(stored), ""); + hdl_assert(cd.clk, data_out.cmp_eq(stored), ""); // Also, accept new data, if any. Otherwise, // let the holding register become empty. connect(stored_reg, inp_firing_data); @@ -417,17 +417,17 @@ mod tests { connect(dut.dbg.index_to_check, index_to_check); #[hdl] if let HdlSome(stored) = stored_reg { - hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), ""); + hdl_assert(cd.clk, stored.cmp_eq(dut.dbg.stored), ""); } // sync the read and write indices - hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), ""); - hdl_assert(clk, out_index_reg.cmp_eq(dut.dbg.out_index), ""); + hdl_assert(cd.clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), ""); + hdl_assert(cd.clk, out_index_reg.cmp_eq(dut.dbg.out_index), ""); // the indices should never go past the capacity, but induction // doesn't know that... - hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), ""); - hdl_assert(clk, out_index_reg.cmp_lt(capacity.get()), ""); + hdl_assert(cd.clk, inp_index_reg.cmp_lt(capacity.get()), ""); + hdl_assert(cd.clk, out_index_reg.cmp_lt(capacity.get()), ""); // strongly constrain the state of the holding register // @@ -455,7 +455,7 @@ mod tests { connect(expected_stored, pending_reads.cmp_lt(dut.count)); // sync with the state of the holding register hdl_assert( - clk, + cd.clk, expected_stored.cmp_eq(HdlOption::is_some(stored_reg)), "", ); diff --git a/crates/fayalite/src/util/union_find_map.rs b/crates/fayalite/src/util/union_find_map.rs new file mode 100644 index 0000000..d197a61 --- /dev/null +++ b/crates/fayalite/src/util/union_find_map.rs @@ -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> { + uf: UnionFind, + keys_to_indexes: M, + values: Vec>, + _phantom: PhantomData, +} + +impl> fmt::Debug + for UnionFindMap +{ + 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("<>") + })); + } + 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> UnionFindMap { + /// 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(&self, k1: &K1, k2: &K2) -> bool + where + M: MapGet + MapGet, + { + self.try_equiv(k1, k2).expect("key not found") + } + pub fn try_equiv(&self, k1: &K1, k2: &K2) -> Option + where + M: MapGet + MapGet, + { + 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(&self, k: &Q) -> &V + where + M: MapGet, + { + self.try_find(k).expect("key not found") + } + pub fn try_find(&self, k: &Q) -> Option<&V> + where + M: MapGet, + { + let &index = self.keys_to_indexes.get(k)?; + self.values[self.uf.find(index)].as_ref() + } + #[track_caller] + pub fn find_mut(&mut self, k: &Q) -> &mut V + where + M: MapGet, + { + self.try_find_mut(k).expect("key not found") + } + pub fn try_find_mut(&mut self, k: &Q) -> Option<&mut V> + where + M: MapGet, + { + 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 { + 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( + &mut self, + k1: &K1, + k2: &K2, + merge: F, + ) -> Option<(bool, &mut V)> + where + M: MapGet + MapGet, + 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(&mut self, k1: &K1, k2: &K2, merge: F) -> (bool, &mut V) + where + M: MapGet + MapGet, + F: FnOnce(&K1, V, &K2, V) -> V, + { + self.try_union(k1, k2, merge).expect("key not found") + } +} + +impl UnionFindMap { + 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 UnionFindMap> { + pub const fn new_btree() -> Self { + Self { + uf: UnionFind::new_empty(), + keys_to_indexes: BTreeMap::new(), + values: Vec::new(), + _phantom: PhantomData, + } + } +} + +impl UnionFindMap> { + 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 Default for UnionFindMap { + 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 + 'a> { + keys_to_indexes_entry: M::OccupiedEntry<'a>, + set_index: usize, + values: &'a mut [Option], +} + +impl<'a, K, V, M: Map + '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 + 'a> { + keys_to_indexes_entry: M::VacantEntry<'a>, + uf: &'a mut UnionFind, + values: &'a mut Vec>, +} + +impl<'a, K, V, M: Map + '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 + 'a> { + Vacant(VacantEntry<'a, K, V, M>), + Occupied(OccupiedEntry<'a, K, V, M>), +} + +impl<'a, K, V, M: Map + 'a> Entry<'a, K, V, M> { + pub fn and_modify(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 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 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(), + } + } +} diff --git a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs b/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs index 2d498e7..620e78c 100644 --- a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs +++ b/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs @@ -595,6 +595,9 @@ impl Visitor for XdcFileWriter { v, instance.source_location(), )? {}, + TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => { + unreachable!("base.is_valid_annotation_target() is known to be false") + } } } } diff --git a/crates/fayalite/src/wire.rs b/crates/fayalite/src/wire.rs index a350d9a..d167c5f 100644 --- a/crates/fayalite/src/wire.rs +++ b/crates/fayalite/src/wire.rs @@ -58,11 +58,13 @@ impl Wire { ty: T::from_canonical(ty), } } + #[track_caller] pub fn new_unchecked( scoped_name: ScopedNameId, source_location: SourceLocation, ty: T, ) -> Self { + scoped_name.0.assert_is_name_id(); Self { name: scoped_name, source_location, @@ -76,7 +78,7 @@ impl Wire { self.containing_module_name_id().0 } pub fn containing_module_name_id(&self) -> NameId { - self.name.0 + self.name.0.unwrap_name_id() } pub fn name(&self) -> Interned { self.name_id().0 diff --git a/crates/fayalite/tests/deduce_structural_eq_flags.rs b/crates/fayalite/tests/deduce_structural_eq_flags.rs new file mode 100644 index 0000000..1d43a0c --- /dev/null +++ b/crates/fayalite/tests/deduce_structural_eq_flags.rs @@ -0,0 +1,4247 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information +use fayalite::{ + assert_export_firrtl, + expr::{ExprEnum, ops::StructuralEq, target::GetTarget}, + firrtl::ExportOptions, + intern::Intern, + module::{ + StmtConnect, + transform::{ + deduce_structural_eq_flags::deduce_structural_eq_flags_with_debug_tracing, + simplify_enums::{SimplifyEnumsKind, simplify_enums}, + visit::{Visit, Visitor}, + }, + }, + prelude::*, +}; +use std::convert::Infallible; + +#[hdl(outline_generated)] +struct CheckStructuralEqOut { + opt_unit_flip: Bool, + opt_unit: Bool, + opt_bool_flip: Bool, + opt_bool: Bool, + opt_opt_unit_flip: Bool, + opt_opt_unit: Bool, + array_opt_bool_flip: Bool, + array_opt_bool: Bool, + struct_opt_bool_flip: Bool, + struct_opt_bool: Bool, +} + +#[hdl(outline_generated)] +struct CheckStructuralEqModuleIO { + #[hdl(flip)] + opt_unit_flip: HdlOption<()>, + opt_unit: HdlOption<()>, + #[hdl(flip)] + opt_bool_flip: HdlOption, + opt_bool: HdlOption, + #[hdl(flip)] + opt_opt_unit_flip: HdlOption>, + opt_opt_unit: HdlOption>, + #[hdl(flip)] + array_opt_bool_flip: Array, 2>, + array_opt_bool: Array, 2>, + #[hdl(flip)] + struct_opt_bool_flip: (HdlOption, Bool), + struct_opt_bool: (HdlOption, Bool), +} + +#[hdl_module(extern, outline_generated)] +fn check_deduce_structural_eq_flags_extern_child() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.output(); +} + +#[hdl_module(outline_generated)] +fn check_deduce_structural_eq_flags_child() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.output(); + #[hdl] + let CheckStructuralEqModuleIO { + opt_unit_flip, + opt_unit, + opt_bool_flip, + opt_bool, + opt_opt_unit_flip, + opt_opt_unit, + array_opt_bool_flip, + array_opt_bool, + struct_opt_bool_flip, + struct_opt_bool, + } = io; + connect(opt_unit, opt_unit_flip); + connect(opt_bool, opt_bool_flip); + connect(opt_opt_unit, opt_opt_unit_flip); + connect(array_opt_bool, array_opt_bool_flip); + connect(struct_opt_bool, struct_opt_bool_flip); +} + +#[hdl_module(outline_generated)] +fn check_deduce_structural_eq_flags_parent() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.input(); + #[hdl] + let io_zeros: CheckStructuralEqModuleIO = m.input(); + #[hdl] + let io_alternating: CheckStructuralEqModuleIO = m.input(); + + #[hdl] + let parent_out: CheckStructuralEqOut = m.output(); + #[hdl] + let parent_zeros_out: CheckStructuralEqOut = m.output(); + #[hdl] + let parent_alternating_out: CheckStructuralEqOut = m.output(); + #[hdl] + let extern_child_out: CheckStructuralEqOut = m.output(); + #[hdl] + let child_out: CheckStructuralEqOut = m.output(); + + #[hdl] + let extern_child = instance(check_deduce_structural_eq_flags_extern_child()); + #[hdl] + let child = instance(check_deduce_structural_eq_flags_child()); + + trait MapLiteral { + fn map_literal(&self, expr: impl ToExpr) -> Expr; + } + + impl) -> Expr> MapLiteral for F { + fn map_literal(&self, expr: impl ToExpr) -> Expr { + Expr::from_canonical(self(Expr::canonical(expr.to_expr()))) + } + } + + #[hdl] + fn connect_io( + io_in: Expr, + out: Expr, + map_literal: impl MapLiteral, + ) { + #[hdl] + let CheckStructuralEqModuleIO { + opt_unit_flip, + opt_unit, + opt_bool_flip, + opt_bool, + opt_opt_unit_flip, + opt_opt_unit, + array_opt_bool_flip, + array_opt_bool, + struct_opt_bool_flip, + struct_opt_bool, + } = io_in; + macro_rules! connect_pair { + ($field_flip:ident, $field:ident, $literal:expr $(,)?) => { + let literal = map_literal.map_literal($literal); + connect($field_flip, literal); + connect( + out.$field, + StructuralEq::new(Expr::canonical($field), Expr::canonical(literal)), + ); + connect( + out.$field_flip, + StructuralEq::new(Expr::canonical($field_flip), Expr::canonical(literal)), + ); + }; + } + connect_pair!(opt_unit_flip, opt_unit, HdlSome(())); + connect_pair!(opt_bool_flip, opt_bool, HdlSome(true)); + connect_pair!(opt_opt_unit_flip, opt_opt_unit, HdlSome(HdlSome(()))); + connect_pair!( + array_opt_bool_flip, + array_opt_bool, + [HdlSome(false), HdlSome(true)], + ); + connect_pair!(struct_opt_bool_flip, struct_opt_bool, (HdlSome(true), true)); + }; + + connect_io(io, parent_out, |expr| expr); + connect_io(io_zeros, parent_zeros_out, |expr: Expr| { + let ty = expr.ty(); + let bits = UInt[ty.bit_width()].zero().to_expr(); + bits.cast_bits_to(ty) + }); + connect_io( + io_alternating, + parent_alternating_out, + |expr: Expr| { + let ty = expr.ty(); + let bits = u128::from_le_bytes([0xAA; _]) + .cast_to(UInt[ty.bit_width()]) + .to_expr(); + bits.cast_bits_to(ty) + }, + ); + connect_io(extern_child.io, extern_child_out, |expr| expr); + connect_io(child.io, child_out, |expr| expr); +} + +#[test] +fn test_deduce_structural_eq_flags() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = check_deduce_structural_eq_flags_parent(); + dbg!(m); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {} + type Ty1 = {|HdlNone, HdlSome: Ty0|} + type Ty2 = {|HdlNone, HdlSome: UInt<1>|} + type Ty3 = {|HdlNone, HdlSome: Ty1|} + type Ty4 = {`0`: Ty2, `1`: UInt<1>} + type Ty5 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty3, opt_opt_unit: Ty3, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty4, struct_opt_bool: Ty4} + type Ty6 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty7 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty8 = {io: Ty5} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty5 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty5 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty5 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty6 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty6 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty6 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty6 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty6 @[module-XXXXXXXXXX.rs 9:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + invalidate _bundle_literal_expr + connect io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome): + connect _cast_enum_to_bits_expr, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr): + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_1): + connect _cast_enum_to_bits_expr_1, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_2): + connect _cast_enum_to_bits_expr_2, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_3: UInt<2> + match io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_3): + connect _cast_enum_to_bits_expr_3, pad(cat(_cast_enum_to_bits_expr_HdlSome_3, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_4: UInt<2> + match {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)): + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_4): + connect _cast_enum_to_bits_expr_4, pad(cat(_cast_enum_to_bits_expr_HdlSome_4, UInt<1>(1)), 2) + connect parent_out.opt_bool, eq(_cast_enum_to_bits_expr_3, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_5: UInt<2> + match io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_5): + connect _cast_enum_to_bits_expr_5, pad(cat(_cast_enum_to_bits_expr_HdlSome_5, UInt<1>(1)), 2) + connect parent_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_5, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_6: UInt<2> + match io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_6): + wire _cast_enum_to_bits_expr_7: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_6: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_7): + connect _cast_enum_to_bits_expr_7, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_6, pad(cat(_cast_enum_to_bits_expr_7, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_8: UInt<2> + match {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)): + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_8): + wire _cast_enum_to_bits_expr_9: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_8: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_9): + connect _cast_enum_to_bits_expr_9, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_8, pad(cat(_cast_enum_to_bits_expr_9, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_6, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_10: UInt<2> + match io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_10): + wire _cast_enum_to_bits_expr_11: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_10: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_11): + connect _cast_enum_to_bits_expr_11, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_10, pad(cat(_cast_enum_to_bits_expr_11, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_10, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + connect _array_literal_expr[0], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h0)) + connect _array_literal_expr[1], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_12: UInt<2> + match io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_12): + connect _cast_enum_to_bits_expr_12, pad(cat(_cast_enum_to_bits_expr_HdlSome_12, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_13: UInt<2> + match _array_literal_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_13): + connect _cast_enum_to_bits_expr_13, pad(cat(_cast_enum_to_bits_expr_HdlSome_13, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_14: UInt<2> + match io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_14): + connect _cast_enum_to_bits_expr_14, pad(cat(_cast_enum_to_bits_expr_HdlSome_14, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_15: UInt<2> + match _array_literal_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_15): + connect _cast_enum_to_bits_expr_15, pad(cat(_cast_enum_to_bits_expr_HdlSome_15, UInt<1>(1)), 2) + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_enum_to_bits_expr_12, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_14, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool, _array_structural_eq @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_16: UInt<2> + match io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_16): + connect _cast_enum_to_bits_expr_16, pad(cat(_cast_enum_to_bits_expr_HdlSome_16, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_17: UInt<2> + match io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_17): + connect _cast_enum_to_bits_expr_17, pad(cat(_cast_enum_to_bits_expr_HdlSome_17, UInt<1>(1)), 2) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_17, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool_flip, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_1: Ty4 + connect _bundle_literal_expr_1.`0`, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect _bundle_literal_expr_1.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_18: UInt<2> + match io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_18): + connect _cast_enum_to_bits_expr_18, pad(cat(_cast_enum_to_bits_expr_HdlSome_18, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_19: UInt<2> + match _bundle_literal_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_19): + connect _cast_enum_to_bits_expr_19, pad(cat(_cast_enum_to_bits_expr_HdlSome_19, UInt<1>(1)), 2) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr_18, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool, _bundle_structural_eq @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_20: UInt<2> + match io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_20): + connect _cast_enum_to_bits_expr_20, pad(cat(_cast_enum_to_bits_expr_HdlSome_20, UInt<1>(1)), 2) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_20, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_enum_expr: Ty1 + when eq(UInt<1>(0), tail(UInt<1>(0h0), 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + wire _cast_bits_to_bundle_expr: Ty0 + invalidate _cast_bits_to_bundle_expr + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect io_zeros.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_21): + connect _cast_enum_to_bits_expr_21, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_enum_expr: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_22): + connect _cast_enum_to_bits_expr_22, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit, eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_zeros.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_23): + connect _cast_enum_to_bits_expr_23, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_1: Ty2 + wire _cast_bits_to_enum_expr_body_1: UInt<1> + connect _cast_bits_to_enum_expr_body_1, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_1) + connect io_zeros.opt_bool_flip, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_24: UInt<2> + match io_zeros.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_24): + connect _cast_enum_to_bits_expr_24, pad(cat(_cast_enum_to_bits_expr_HdlSome_24, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_25: UInt<2> + match _cast_bits_to_enum_expr_1: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_25): + connect _cast_enum_to_bits_expr_25, pad(cat(_cast_enum_to_bits_expr_HdlSome_25, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool, eq(_cast_enum_to_bits_expr_24, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_26: UInt<2> + match io_zeros.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_26): + connect _cast_enum_to_bits_expr_26, pad(cat(_cast_enum_to_bits_expr_HdlSome_26, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_2: Ty3 + wire _cast_bits_to_enum_expr_body_2: UInt<1> + connect _cast_bits_to_enum_expr_body_2, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_3: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_2, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_3) + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_enum_expr_2 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_27: UInt<2> + match io_zeros.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_27): + wire _cast_enum_to_bits_expr_28: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_27: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_28): + connect _cast_enum_to_bits_expr_28, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_27, pad(cat(_cast_enum_to_bits_expr_28, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_29: UInt<2> + match _cast_bits_to_enum_expr_2: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_29): + wire _cast_enum_to_bits_expr_30: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_29: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_30): + connect _cast_enum_to_bits_expr_30, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_29, pad(cat(_cast_enum_to_bits_expr_30, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_31: UInt<2> + match io_zeros.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_31): + wire _cast_enum_to_bits_expr_32: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_31: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_32): + connect _cast_enum_to_bits_expr_32, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_31, pad(cat(_cast_enum_to_bits_expr_32, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_4: Ty2 + wire _cast_bits_to_enum_expr_body_4: UInt<1> + connect _cast_bits_to_enum_expr_body_4, head(_cast_bits_to_array_expr_flattened[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[0], 1)): + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_4) + connect _cast_bits_to_array_expr[0], _cast_bits_to_enum_expr_4 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_enum_expr_5: Ty2 + wire _cast_bits_to_enum_expr_body_5: UInt<1> + connect _cast_bits_to_enum_expr_body_5, head(_cast_bits_to_array_expr_flattened[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[1], 1)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_5) + connect _cast_bits_to_array_expr[1], _cast_bits_to_enum_expr_5 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_33: UInt<2> + match io_zeros.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_33): + connect _cast_enum_to_bits_expr_33, pad(cat(_cast_enum_to_bits_expr_HdlSome_33, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_34: UInt<2> + match _cast_bits_to_array_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_34): + connect _cast_enum_to_bits_expr_34, pad(cat(_cast_enum_to_bits_expr_HdlSome_34, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_35: UInt<2> + match io_zeros.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_35): + connect _cast_enum_to_bits_expr_35, pad(cat(_cast_enum_to_bits_expr_HdlSome_35, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_36: UInt<2> + match _cast_bits_to_array_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_36): + connect _cast_enum_to_bits_expr_36, pad(cat(_cast_enum_to_bits_expr_HdlSome_36, UInt<1>(1)), 2) + wire _array_structural_eq_2: UInt<1> + connect _array_structural_eq_2, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool, _array_structural_eq_2 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_37: UInt<2> + match io_zeros.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_37): + connect _cast_enum_to_bits_expr_37, pad(cat(_cast_enum_to_bits_expr_HdlSome_37, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_38: UInt<2> + match io_zeros.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_38): + connect _cast_enum_to_bits_expr_38, pad(cat(_cast_enum_to_bits_expr_HdlSome_38, UInt<1>(1)), 2) + wire _array_structural_eq_3: UInt<1> + connect _array_structural_eq_3, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool_flip, _array_structural_eq_3 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_6: Ty2 + wire _cast_bits_to_enum_expr_body_6: UInt<1> + connect _cast_bits_to_enum_expr_body_6, head(_cast_bits_to_bundle_expr_flattened.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.`0`, 1)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_6) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_39: UInt<2> + match io_zeros.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_39): + connect _cast_enum_to_bits_expr_39, pad(cat(_cast_enum_to_bits_expr_HdlSome_39, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_40: UInt<2> + match _cast_bits_to_bundle_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_40): + connect _cast_enum_to_bits_expr_40, pad(cat(_cast_enum_to_bits_expr_HdlSome_40, UInt<1>(1)), 2) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_41: UInt<2> + match io_zeros.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_41): + connect _cast_enum_to_bits_expr_41, pad(cat(_cast_enum_to_bits_expr_HdlSome_41, UInt<1>(1)), 2) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match io_alternating.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_42): + connect _cast_enum_to_bits_expr_42, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit, eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_43: UInt<1> + match io_alternating.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_43): + connect _cast_enum_to_bits_expr_43, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_7: Ty2 + wire _cast_bits_to_enum_expr_body_7: UInt<1> + connect _cast_bits_to_enum_expr_body_7, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_7) + connect io_alternating.opt_bool_flip, _cast_bits_to_enum_expr_7 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_44: UInt<2> + match io_alternating.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_44): + connect _cast_enum_to_bits_expr_44, pad(cat(_cast_enum_to_bits_expr_HdlSome_44, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_45: UInt<2> + match _cast_bits_to_enum_expr_7: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_45): + connect _cast_enum_to_bits_expr_45, pad(cat(_cast_enum_to_bits_expr_HdlSome_45, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool, eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_46: UInt<2> + match io_alternating.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_46): + connect _cast_enum_to_bits_expr_46, pad(cat(_cast_enum_to_bits_expr_HdlSome_46, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_46, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_8: Ty3 + wire _cast_bits_to_enum_expr_body_8: UInt<1> + connect _cast_bits_to_enum_expr_body_8, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_9: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_8, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_9) + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_enum_expr_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_47: UInt<2> + match io_alternating.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_47): + wire _cast_enum_to_bits_expr_48: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_47: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_48): + connect _cast_enum_to_bits_expr_48, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_47, pad(cat(_cast_enum_to_bits_expr_48, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_49: UInt<2> + match _cast_bits_to_enum_expr_8: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_49): + wire _cast_enum_to_bits_expr_50: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_49: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_50): + connect _cast_enum_to_bits_expr_50, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_49, pad(cat(_cast_enum_to_bits_expr_50, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_51: UInt<2> + match io_alternating.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_51): + wire _cast_enum_to_bits_expr_52: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_51: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_52): + connect _cast_enum_to_bits_expr_52, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_51, pad(cat(_cast_enum_to_bits_expr_52, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_enum_expr_10: Ty2 + wire _cast_bits_to_enum_expr_body_10: UInt<1> + connect _cast_bits_to_enum_expr_body_10, head(_cast_bits_to_array_expr_flattened_1[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[0], 1)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_10) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_enum_expr_10 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_enum_expr_11: Ty2 + wire _cast_bits_to_enum_expr_body_11: UInt<1> + connect _cast_bits_to_enum_expr_body_11, head(_cast_bits_to_array_expr_flattened_1[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[1], 1)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_11) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_enum_expr_11 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_53: UInt<2> + match io_alternating.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_53): + connect _cast_enum_to_bits_expr_53, pad(cat(_cast_enum_to_bits_expr_HdlSome_53, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_54: UInt<2> + match _cast_bits_to_array_expr_1[0]: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_54): + connect _cast_enum_to_bits_expr_54, pad(cat(_cast_enum_to_bits_expr_HdlSome_54, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_55: UInt<2> + match io_alternating.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_55): + connect _cast_enum_to_bits_expr_55, pad(cat(_cast_enum_to_bits_expr_HdlSome_55, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_56: UInt<2> + match _cast_bits_to_array_expr_1[1]: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_56): + connect _cast_enum_to_bits_expr_56, pad(cat(_cast_enum_to_bits_expr_HdlSome_56, UInt<1>(1)), 2) + wire _array_structural_eq_4: UInt<1> + connect _array_structural_eq_4, and(eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool, _array_structural_eq_4 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_57: UInt<2> + match io_alternating.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_57): + connect _cast_enum_to_bits_expr_57, pad(cat(_cast_enum_to_bits_expr_HdlSome_57, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_58: UInt<2> + match io_alternating.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_58): + connect _cast_enum_to_bits_expr_58, pad(cat(_cast_enum_to_bits_expr_HdlSome_58, UInt<1>(1)), 2) + wire _array_structural_eq_5: UInt<1> + connect _array_structural_eq_5, and(eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool_flip, _array_structural_eq_5 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty7 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_enum_expr_12: Ty2 + wire _cast_bits_to_enum_expr_body_12: UInt<1> + connect _cast_bits_to_enum_expr_body_12, head(_cast_bits_to_bundle_expr_flattened_1.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.`0`, 1)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_12) + connect _cast_bits_to_bundle_expr_2.`0`, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_2.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_59: UInt<2> + match io_alternating.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_59): + connect _cast_enum_to_bits_expr_59, pad(cat(_cast_enum_to_bits_expr_HdlSome_59, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_60: UInt<2> + match _cast_bits_to_bundle_expr_2.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_60): + connect _cast_enum_to_bits_expr_60, pad(cat(_cast_enum_to_bits_expr_HdlSome_60, UInt<1>(1)), 2) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool, _bundle_structural_eq_4 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_61: UInt<2> + match io_alternating.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_61): + connect _cast_enum_to_bits_expr_61, pad(cat(_cast_enum_to_bits_expr_HdlSome_61, UInt<1>(1)), 2) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_61, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool_flip, _bundle_structural_eq_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match extern_child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_62): + connect _cast_enum_to_bits_expr_62, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit, eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_63: UInt<1> + match extern_child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_63): + connect _cast_enum_to_bits_expr_63, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_64: UInt<2> + match extern_child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_64): + connect _cast_enum_to_bits_expr_64, pad(cat(_cast_enum_to_bits_expr_HdlSome_64, UInt<1>(1)), 2) + connect extern_child_out.opt_bool, eq(_cast_enum_to_bits_expr_64, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_65: UInt<2> + match extern_child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_65): + connect _cast_enum_to_bits_expr_65, pad(cat(_cast_enum_to_bits_expr_HdlSome_65, UInt<1>(1)), 2) + connect extern_child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_65, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_66: UInt<2> + match extern_child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_66): + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_66: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_67): + connect _cast_enum_to_bits_expr_67, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_66, pad(cat(_cast_enum_to_bits_expr_67, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_68: UInt<2> + match extern_child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_68): + wire _cast_enum_to_bits_expr_69: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_68: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_69): + connect _cast_enum_to_bits_expr_69, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_68, pad(cat(_cast_enum_to_bits_expr_69, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_68, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_70: UInt<2> + match extern_child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_70): + connect _cast_enum_to_bits_expr_70, pad(cat(_cast_enum_to_bits_expr_HdlSome_70, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_71: UInt<2> + match extern_child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_71): + connect _cast_enum_to_bits_expr_71, pad(cat(_cast_enum_to_bits_expr_HdlSome_71, UInt<1>(1)), 2) + wire _array_structural_eq_6: UInt<1> + connect _array_structural_eq_6, and(eq(_cast_enum_to_bits_expr_70, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_71, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool, _array_structural_eq_6 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_72: UInt<2> + match extern_child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_72): + connect _cast_enum_to_bits_expr_72, pad(cat(_cast_enum_to_bits_expr_HdlSome_72, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_73: UInt<2> + match extern_child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_73): + connect _cast_enum_to_bits_expr_73, pad(cat(_cast_enum_to_bits_expr_HdlSome_73, UInt<1>(1)), 2) + wire _array_structural_eq_7: UInt<1> + connect _array_structural_eq_7, and(eq(_cast_enum_to_bits_expr_72, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool_flip, _array_structural_eq_7 @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_74: UInt<2> + match extern_child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_74): + connect _cast_enum_to_bits_expr_74, pad(cat(_cast_enum_to_bits_expr_HdlSome_74, UInt<1>(1)), 2) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_75: UInt<2> + match extern_child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_75): + connect _cast_enum_to_bits_expr_75, pad(cat(_cast_enum_to_bits_expr_HdlSome_75, UInt<1>(1)), 2) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_75, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_76: UInt<1> + match child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_76): + connect _cast_enum_to_bits_expr_76, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit, eq(_cast_enum_to_bits_expr_76, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_77): + connect _cast_enum_to_bits_expr_77, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_78: UInt<2> + match child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_78): + connect _cast_enum_to_bits_expr_78, pad(cat(_cast_enum_to_bits_expr_HdlSome_78, UInt<1>(1)), 2) + connect child_out.opt_bool, eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_79: UInt<2> + match child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_79): + connect _cast_enum_to_bits_expr_79, pad(cat(_cast_enum_to_bits_expr_HdlSome_79, UInt<1>(1)), 2) + connect child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_80: UInt<2> + match child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_80): + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_80: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_81): + connect _cast_enum_to_bits_expr_81, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_80, pad(cat(_cast_enum_to_bits_expr_81, UInt<1>(1)), 2) + connect child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_82: UInt<2> + match child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_82): + wire _cast_enum_to_bits_expr_83: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_82: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_83): + connect _cast_enum_to_bits_expr_83, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_82, pad(cat(_cast_enum_to_bits_expr_83, UInt<1>(1)), 2) + connect child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_84: UInt<2> + match child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_84): + connect _cast_enum_to_bits_expr_84, pad(cat(_cast_enum_to_bits_expr_HdlSome_84, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_85: UInt<2> + match child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_85, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_85): + connect _cast_enum_to_bits_expr_85, pad(cat(_cast_enum_to_bits_expr_HdlSome_85, UInt<1>(1)), 2) + wire _array_structural_eq_8: UInt<1> + connect _array_structural_eq_8, and(eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_85, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool, _array_structural_eq_8 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_86: UInt<2> + match child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_86, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_86): + connect _cast_enum_to_bits_expr_86, pad(cat(_cast_enum_to_bits_expr_HdlSome_86, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_87: UInt<2> + match child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_87, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_87): + connect _cast_enum_to_bits_expr_87, pad(cat(_cast_enum_to_bits_expr_HdlSome_87, UInt<1>(1)), 2) + wire _array_structural_eq_9: UInt<1> + connect _array_structural_eq_9, and(eq(_cast_enum_to_bits_expr_86, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_87, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool_flip, _array_structural_eq_9 @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_88: UInt<2> + match child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_88, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_88): + connect _cast_enum_to_bits_expr_88, pad(cat(_cast_enum_to_bits_expr_HdlSome_88, UInt<1>(1)), 2) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_88, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_89: UInt<2> + match child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_89, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_89): + connect _cast_enum_to_bits_expr_89, pad(cat(_cast_enum_to_bits_expr_HdlSome_89, UInt<1>(1)), 2) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_89, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 17:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m = deduce_structural_eq_flags_with_debug_tracing(m.canonical().intern_sized(), true); + dbg!(m); + struct MyVisitor(Vec<(String, bool)>); + macro_rules! connects { + {$($key:literal: $value:literal),* $(,)?} => { + const KNOWN_CONNECTS: &[(&str, bool)] = &[$(($key, $value)),*]; + }; + } + + connects! { + "check_deduce_structural_eq_flags_parent::parent_out.opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_opt_unit_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.array_opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.struct_opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_unit": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_opt_unit": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.array_opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.struct_opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.struct_opt_bool_flip": true, + } + + impl Visitor for MyVisitor { + type Error = Infallible; + fn visit_stmt_connect(&mut self, v: &StmtConnect) -> Result<(), Self::Error> { + let ExprEnum::StructuralEq(structural_eq) = *Expr::expr_enum(v.rhs) else { + return v.default_visit(self); + }; + let Some(lhs_target) = v.lhs.target() else { + panic!("connect lhs must have a Target: {v:#?}"); + }; + let lhs_target_str = lhs_target.to_string(); + let assume_padding_is_zeroed = structural_eq.flags().assume_padding_is_zeroed; + if let Some(key) = KNOWN_CONNECTS + .iter() + .copied() + .find(|&(key, _)| key == lhs_target_str) + { + if assume_padding_is_zeroed != key.1 { + println!("{key:?}: {v:#?}"); + panic!( + "{key:?}: assume_padding_is_zeroed ({assume_padding_is_zeroed}) is not as expected" + ); + } + } else { + let k = (lhs_target_str, assume_padding_is_zeroed); + println!("{k:?}: {v:#?}"); + self.0.push(k); + } + Ok(()) + } + } + let mut visitor = MyVisitor(vec![]); + let Ok(()) = visitor.visit_module(&m); + if !visitor.0.is_empty() { + panic!( + "unknown connects:\nconnects! {:#?}", + std::fmt::from_fn(|f| { f.debug_map().entries(visitor.0.iter().cloned()).finish() }) + ) + } + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {} + type Ty1 = {|HdlNone, HdlSome: Ty0|} + type Ty2 = {|HdlNone, HdlSome: UInt<1>|} + type Ty3 = {|HdlNone, HdlSome: Ty1|} + type Ty4 = {`0`: Ty2, `1`: UInt<1>} + type Ty5 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty3, opt_opt_unit: Ty3, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty4, struct_opt_bool: Ty4} + type Ty6 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty7 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty8 = {io: Ty5} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty5 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty5 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty5 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty6 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty6 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty6 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty6 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty6 @[module-XXXXXXXXXX.rs 9:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + invalidate _bundle_literal_expr + connect io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome): + connect _cast_enum_to_bits_expr, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr): + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_1): + connect _cast_enum_to_bits_expr_1, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_2): + connect _cast_enum_to_bits_expr_2, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_3: UInt<2> + match io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_3): + connect _cast_enum_to_bits_expr_3, pad(cat(_cast_enum_to_bits_expr_HdlSome_3, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_4: UInt<2> + match {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)): + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_4): + connect _cast_enum_to_bits_expr_4, pad(cat(_cast_enum_to_bits_expr_HdlSome_4, UInt<1>(1)), 2) + connect parent_out.opt_bool, eq(_cast_enum_to_bits_expr_3, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_5: UInt<2> + match io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_5): + connect _cast_enum_to_bits_expr_5, pad(cat(_cast_enum_to_bits_expr_HdlSome_5, UInt<1>(1)), 2) + connect parent_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_5, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_6: UInt<2> + match io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_6): + wire _cast_enum_to_bits_expr_7: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_6: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_7): + connect _cast_enum_to_bits_expr_7, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_6, pad(cat(_cast_enum_to_bits_expr_7, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_8: UInt<2> + match {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)): + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_8): + wire _cast_enum_to_bits_expr_9: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_8: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_9): + connect _cast_enum_to_bits_expr_9, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_8, pad(cat(_cast_enum_to_bits_expr_9, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_6, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_10: UInt<2> + match io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_10): + wire _cast_enum_to_bits_expr_11: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_10: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_11): + connect _cast_enum_to_bits_expr_11, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_10, pad(cat(_cast_enum_to_bits_expr_11, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_10, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + connect _array_literal_expr[0], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h0)) + connect _array_literal_expr[1], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_12: UInt<2> + match io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_12): + connect _cast_enum_to_bits_expr_12, pad(cat(_cast_enum_to_bits_expr_HdlSome_12, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_13: UInt<2> + match _array_literal_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_13): + connect _cast_enum_to_bits_expr_13, pad(cat(_cast_enum_to_bits_expr_HdlSome_13, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_14: UInt<2> + match io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_14): + connect _cast_enum_to_bits_expr_14, pad(cat(_cast_enum_to_bits_expr_HdlSome_14, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_15: UInt<2> + match _array_literal_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_15): + connect _cast_enum_to_bits_expr_15, pad(cat(_cast_enum_to_bits_expr_HdlSome_15, UInt<1>(1)), 2) + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_enum_to_bits_expr_12, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_14, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool, _array_structural_eq @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_16: UInt<2> + match io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_16): + connect _cast_enum_to_bits_expr_16, pad(cat(_cast_enum_to_bits_expr_HdlSome_16, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_17: UInt<2> + match io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_17): + connect _cast_enum_to_bits_expr_17, pad(cat(_cast_enum_to_bits_expr_HdlSome_17, UInt<1>(1)), 2) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_17, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool_flip, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_1: Ty4 + connect _bundle_literal_expr_1.`0`, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect _bundle_literal_expr_1.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_18: UInt<2> + match io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_18): + connect _cast_enum_to_bits_expr_18, pad(cat(_cast_enum_to_bits_expr_HdlSome_18, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_19: UInt<2> + match _bundle_literal_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_19): + connect _cast_enum_to_bits_expr_19, pad(cat(_cast_enum_to_bits_expr_HdlSome_19, UInt<1>(1)), 2) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr_18, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool, _bundle_structural_eq @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_20: UInt<2> + match io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_20): + connect _cast_enum_to_bits_expr_20, pad(cat(_cast_enum_to_bits_expr_HdlSome_20, UInt<1>(1)), 2) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_20, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_enum_expr: Ty1 + when eq(UInt<1>(0), tail(UInt<1>(0h0), 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + wire _cast_bits_to_bundle_expr: Ty0 + invalidate _cast_bits_to_bundle_expr + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect io_zeros.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_21): + connect _cast_enum_to_bits_expr_21, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_enum_expr: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_22): + connect _cast_enum_to_bits_expr_22, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit, eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_zeros.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_23): + connect _cast_enum_to_bits_expr_23, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_1: Ty2 + wire _cast_bits_to_enum_expr_body_1: UInt<1> + connect _cast_bits_to_enum_expr_body_1, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_1) + connect io_zeros.opt_bool_flip, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_24: UInt<2> + match io_zeros.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_24): + connect _cast_enum_to_bits_expr_24, pad(cat(_cast_enum_to_bits_expr_HdlSome_24, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_25: UInt<2> + match _cast_bits_to_enum_expr_1: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_25): + connect _cast_enum_to_bits_expr_25, pad(cat(_cast_enum_to_bits_expr_HdlSome_25, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool, eq(_cast_enum_to_bits_expr_24, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_26: UInt<2> + match io_zeros.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_26): + connect _cast_enum_to_bits_expr_26, pad(cat(_cast_enum_to_bits_expr_HdlSome_26, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_2: Ty3 + wire _cast_bits_to_enum_expr_body_2: UInt<1> + connect _cast_bits_to_enum_expr_body_2, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_3: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_2, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_3) + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_enum_expr_2 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_27: UInt<2> + match io_zeros.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_27): + wire _cast_enum_to_bits_expr_28: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_27: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_28): + connect _cast_enum_to_bits_expr_28, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_27, pad(cat(_cast_enum_to_bits_expr_28, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_29: UInt<2> + match _cast_bits_to_enum_expr_2: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_29): + wire _cast_enum_to_bits_expr_30: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_29: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_30): + connect _cast_enum_to_bits_expr_30, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_29, pad(cat(_cast_enum_to_bits_expr_30, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_31: UInt<2> + match io_zeros.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_31): + wire _cast_enum_to_bits_expr_32: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_31: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_32): + connect _cast_enum_to_bits_expr_32, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_31, pad(cat(_cast_enum_to_bits_expr_32, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_4: Ty2 + wire _cast_bits_to_enum_expr_body_4: UInt<1> + connect _cast_bits_to_enum_expr_body_4, head(_cast_bits_to_array_expr_flattened[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[0], 1)): + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_4) + connect _cast_bits_to_array_expr[0], _cast_bits_to_enum_expr_4 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_enum_expr_5: Ty2 + wire _cast_bits_to_enum_expr_body_5: UInt<1> + connect _cast_bits_to_enum_expr_body_5, head(_cast_bits_to_array_expr_flattened[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[1], 1)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_5) + connect _cast_bits_to_array_expr[1], _cast_bits_to_enum_expr_5 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_33: UInt<2> + match io_zeros.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_33): + connect _cast_enum_to_bits_expr_33, pad(cat(_cast_enum_to_bits_expr_HdlSome_33, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_34: UInt<2> + match _cast_bits_to_array_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_34): + connect _cast_enum_to_bits_expr_34, pad(cat(_cast_enum_to_bits_expr_HdlSome_34, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_35: UInt<2> + match io_zeros.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_35): + connect _cast_enum_to_bits_expr_35, pad(cat(_cast_enum_to_bits_expr_HdlSome_35, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_36: UInt<2> + match _cast_bits_to_array_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_36): + connect _cast_enum_to_bits_expr_36, pad(cat(_cast_enum_to_bits_expr_HdlSome_36, UInt<1>(1)), 2) + wire _array_structural_eq_2: UInt<1> + connect _array_structural_eq_2, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool, _array_structural_eq_2 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_37: UInt<2> + match io_zeros.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_37): + connect _cast_enum_to_bits_expr_37, pad(cat(_cast_enum_to_bits_expr_HdlSome_37, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_38: UInt<2> + match io_zeros.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_38): + connect _cast_enum_to_bits_expr_38, pad(cat(_cast_enum_to_bits_expr_HdlSome_38, UInt<1>(1)), 2) + wire _array_structural_eq_3: UInt<1> + connect _array_structural_eq_3, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool_flip, _array_structural_eq_3 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_6: Ty2 + wire _cast_bits_to_enum_expr_body_6: UInt<1> + connect _cast_bits_to_enum_expr_body_6, head(_cast_bits_to_bundle_expr_flattened.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.`0`, 1)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_6) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_39: UInt<2> + match io_zeros.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_39): + connect _cast_enum_to_bits_expr_39, pad(cat(_cast_enum_to_bits_expr_HdlSome_39, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_40: UInt<2> + match _cast_bits_to_bundle_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_40): + connect _cast_enum_to_bits_expr_40, pad(cat(_cast_enum_to_bits_expr_HdlSome_40, UInt<1>(1)), 2) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_41: UInt<2> + match io_zeros.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_41): + connect _cast_enum_to_bits_expr_41, pad(cat(_cast_enum_to_bits_expr_HdlSome_41, UInt<1>(1)), 2) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match io_alternating.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_42): + connect _cast_enum_to_bits_expr_42, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit, eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_43: UInt<1> + match io_alternating.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_43): + connect _cast_enum_to_bits_expr_43, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_7: Ty2 + wire _cast_bits_to_enum_expr_body_7: UInt<1> + connect _cast_bits_to_enum_expr_body_7, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_7) + connect io_alternating.opt_bool_flip, _cast_bits_to_enum_expr_7 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_44: UInt<2> + match io_alternating.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_44): + connect _cast_enum_to_bits_expr_44, pad(cat(_cast_enum_to_bits_expr_HdlSome_44, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_45: UInt<2> + match _cast_bits_to_enum_expr_7: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_45): + connect _cast_enum_to_bits_expr_45, pad(cat(_cast_enum_to_bits_expr_HdlSome_45, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool, eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_46: UInt<2> + match io_alternating.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_46): + connect _cast_enum_to_bits_expr_46, pad(cat(_cast_enum_to_bits_expr_HdlSome_46, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_46, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_8: Ty3 + wire _cast_bits_to_enum_expr_body_8: UInt<1> + connect _cast_bits_to_enum_expr_body_8, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_9: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_8, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_9) + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_enum_expr_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_47: UInt<2> + match io_alternating.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_47): + wire _cast_enum_to_bits_expr_48: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_47: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_48): + connect _cast_enum_to_bits_expr_48, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_47, pad(cat(_cast_enum_to_bits_expr_48, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_49: UInt<2> + match _cast_bits_to_enum_expr_8: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_49): + wire _cast_enum_to_bits_expr_50: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_49: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_50): + connect _cast_enum_to_bits_expr_50, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_49, pad(cat(_cast_enum_to_bits_expr_50, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_51: UInt<2> + match io_alternating.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_51): + wire _cast_enum_to_bits_expr_52: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_51: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_52): + connect _cast_enum_to_bits_expr_52, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_51, pad(cat(_cast_enum_to_bits_expr_52, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_enum_expr_10: Ty2 + wire _cast_bits_to_enum_expr_body_10: UInt<1> + connect _cast_bits_to_enum_expr_body_10, head(_cast_bits_to_array_expr_flattened_1[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[0], 1)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_10) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_enum_expr_10 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_enum_expr_11: Ty2 + wire _cast_bits_to_enum_expr_body_11: UInt<1> + connect _cast_bits_to_enum_expr_body_11, head(_cast_bits_to_array_expr_flattened_1[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[1], 1)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_11) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_enum_expr_11 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_53: UInt<2> + match io_alternating.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_53): + connect _cast_enum_to_bits_expr_53, pad(cat(_cast_enum_to_bits_expr_HdlSome_53, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_54: UInt<2> + match _cast_bits_to_array_expr_1[0]: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_54): + connect _cast_enum_to_bits_expr_54, pad(cat(_cast_enum_to_bits_expr_HdlSome_54, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_55: UInt<2> + match io_alternating.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_55): + connect _cast_enum_to_bits_expr_55, pad(cat(_cast_enum_to_bits_expr_HdlSome_55, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_56: UInt<2> + match _cast_bits_to_array_expr_1[1]: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_56): + connect _cast_enum_to_bits_expr_56, pad(cat(_cast_enum_to_bits_expr_HdlSome_56, UInt<1>(1)), 2) + wire _array_structural_eq_4: UInt<1> + connect _array_structural_eq_4, and(eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool, _array_structural_eq_4 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_57: UInt<2> + match io_alternating.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_57): + connect _cast_enum_to_bits_expr_57, pad(cat(_cast_enum_to_bits_expr_HdlSome_57, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_58: UInt<2> + match io_alternating.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_58): + connect _cast_enum_to_bits_expr_58, pad(cat(_cast_enum_to_bits_expr_HdlSome_58, UInt<1>(1)), 2) + wire _array_structural_eq_5: UInt<1> + connect _array_structural_eq_5, and(eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool_flip, _array_structural_eq_5 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty7 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_enum_expr_12: Ty2 + wire _cast_bits_to_enum_expr_body_12: UInt<1> + connect _cast_bits_to_enum_expr_body_12, head(_cast_bits_to_bundle_expr_flattened_1.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.`0`, 1)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_12) + connect _cast_bits_to_bundle_expr_2.`0`, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_2.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_59: UInt<2> + match io_alternating.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_59): + connect _cast_enum_to_bits_expr_59, pad(cat(_cast_enum_to_bits_expr_HdlSome_59, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_60: UInt<2> + match _cast_bits_to_bundle_expr_2.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_60): + connect _cast_enum_to_bits_expr_60, pad(cat(_cast_enum_to_bits_expr_HdlSome_60, UInt<1>(1)), 2) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool, _bundle_structural_eq_4 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_61: UInt<2> + match io_alternating.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_61): + connect _cast_enum_to_bits_expr_61, pad(cat(_cast_enum_to_bits_expr_HdlSome_61, UInt<1>(1)), 2) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_61, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool_flip, _bundle_structural_eq_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match extern_child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_62): + connect _cast_enum_to_bits_expr_62, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit, eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_63: UInt<1> + match extern_child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_63): + connect _cast_enum_to_bits_expr_63, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_64: UInt<2> + match extern_child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_64): + connect _cast_enum_to_bits_expr_64, pad(cat(_cast_enum_to_bits_expr_HdlSome_64, UInt<1>(1)), 2) + connect extern_child_out.opt_bool, eq(_cast_enum_to_bits_expr_64, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_65: UInt<2> + match extern_child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_65): + connect _cast_enum_to_bits_expr_65, pad(cat(_cast_enum_to_bits_expr_HdlSome_65, UInt<1>(1)), 2) + connect extern_child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_65, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_66: UInt<2> + match extern_child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_66): + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_66: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_67): + connect _cast_enum_to_bits_expr_67, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_66, pad(cat(_cast_enum_to_bits_expr_67, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_68: UInt<2> + match extern_child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_68): + wire _cast_enum_to_bits_expr_69: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_68: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_69): + connect _cast_enum_to_bits_expr_69, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_68, pad(cat(_cast_enum_to_bits_expr_69, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_68, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_70: UInt<2> + match extern_child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_70): + connect _cast_enum_to_bits_expr_70, pad(cat(_cast_enum_to_bits_expr_HdlSome_70, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_71: UInt<2> + match extern_child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_71): + connect _cast_enum_to_bits_expr_71, pad(cat(_cast_enum_to_bits_expr_HdlSome_71, UInt<1>(1)), 2) + wire _array_structural_eq_6: UInt<1> + connect _array_structural_eq_6, and(eq(_cast_enum_to_bits_expr_70, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_71, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool, _array_structural_eq_6 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_72: UInt<2> + match extern_child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_72): + connect _cast_enum_to_bits_expr_72, pad(cat(_cast_enum_to_bits_expr_HdlSome_72, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_73: UInt<2> + match extern_child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_73): + connect _cast_enum_to_bits_expr_73, pad(cat(_cast_enum_to_bits_expr_HdlSome_73, UInt<1>(1)), 2) + wire _array_structural_eq_7: UInt<1> + connect _array_structural_eq_7, and(eq(_cast_enum_to_bits_expr_72, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool_flip, _array_structural_eq_7 @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_74: UInt<2> + match extern_child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_74): + connect _cast_enum_to_bits_expr_74, pad(cat(_cast_enum_to_bits_expr_HdlSome_74, UInt<1>(1)), 2) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_75: UInt<2> + match extern_child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_75): + connect _cast_enum_to_bits_expr_75, pad(cat(_cast_enum_to_bits_expr_HdlSome_75, UInt<1>(1)), 2) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_75, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_76: UInt<1> + match child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_76): + connect _cast_enum_to_bits_expr_76, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit, eq(_cast_enum_to_bits_expr_76, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_77): + connect _cast_enum_to_bits_expr_77, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_78: UInt<2> + match child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_78): + connect _cast_enum_to_bits_expr_78, pad(cat(_cast_enum_to_bits_expr_HdlSome_78, UInt<1>(1)), 2) + connect child_out.opt_bool, eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_79: UInt<2> + match child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_79): + connect _cast_enum_to_bits_expr_79, pad(cat(_cast_enum_to_bits_expr_HdlSome_79, UInt<1>(1)), 2) + connect child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_80: UInt<2> + match child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_80): + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_80: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_81): + connect _cast_enum_to_bits_expr_81, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_80, pad(cat(_cast_enum_to_bits_expr_81, UInt<1>(1)), 2) + connect child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_82: UInt<2> + match child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_82): + wire _cast_enum_to_bits_expr_83: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_82: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_83): + connect _cast_enum_to_bits_expr_83, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_82, pad(cat(_cast_enum_to_bits_expr_83, UInt<1>(1)), 2) + connect child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_84: UInt<2> + match child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_84): + connect _cast_enum_to_bits_expr_84, pad(cat(_cast_enum_to_bits_expr_HdlSome_84, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_85: UInt<2> + match child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_85, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_85): + connect _cast_enum_to_bits_expr_85, pad(cat(_cast_enum_to_bits_expr_HdlSome_85, UInt<1>(1)), 2) + wire _array_structural_eq_8: UInt<1> + connect _array_structural_eq_8, and(eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_85, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool, _array_structural_eq_8 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_86: UInt<2> + match child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_86, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_86): + connect _cast_enum_to_bits_expr_86, pad(cat(_cast_enum_to_bits_expr_HdlSome_86, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_87: UInt<2> + match child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_87, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_87): + connect _cast_enum_to_bits_expr_87, pad(cat(_cast_enum_to_bits_expr_HdlSome_87, UInt<1>(1)), 2) + wire _array_structural_eq_9: UInt<1> + connect _array_structural_eq_9, and(eq(_cast_enum_to_bits_expr_86, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_87, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool_flip, _array_structural_eq_9 @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_88: UInt<2> + match child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_88, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_88): + connect _cast_enum_to_bits_expr_88, pad(cat(_cast_enum_to_bits_expr_HdlSome_88, UInt<1>(1)), 2) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_88, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_89: UInt<2> + match child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_89, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_89): + connect _cast_enum_to_bits_expr_89, pad(cat(_cast_enum_to_bits_expr_HdlSome_89, UInt<1>(1)), 2) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_89, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 17:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_no_body = simplify_enums(m, SimplifyEnumsKind::SimplifyToEnumsWithNoBody).unwrap(); + dbg!(m_no_body); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_no_body => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {|HdlNone, HdlSome|} + type Ty1 = {tag: Ty0, body: UInt<0>} + type Ty2 = {tag: Ty0, body: UInt<1>} + type Ty3 = {`0`: Ty2, `1`: UInt<1>} + type Ty4 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty2, opt_opt_unit: Ty2, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty3, struct_opt_bool: Ty3} + type Ty5 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty6 = {} + type Ty7 = {tag: UInt<1>, body: UInt<0>} + type Ty8 = {tag: UInt<1>, body: UInt<1>} + type Ty9 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty10 = {io: Ty4} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty4 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty4 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty4 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty5 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty5 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty5 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty5 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty5 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty1 + connect _bundle_literal_expr.tag, {|HdlNone, HdlSome|}(HdlSome) + wire _bundle_literal_expr_1: Ty6 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + connect io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit, __enum_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr, UInt<1>(1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match _bundle_literal_expr.tag: + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_1, UInt<1>(1) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1), eq(io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit_flip, _bundle_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty2 + connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + connect io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_2, UInt<1>(1) + wire _cast_enum_to_bits_expr_3: UInt<1> + match _bundle_literal_expr_2.tag: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_3, UInt<1>(1) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_3), eq(io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect parent_out.opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty2 + connect _bundle_literal_expr_3.tag, {|HdlNone, HdlSome|}(HdlSome) + wire _cast_bundle_to_bits_expr: Ty7 + connect _cast_bundle_to_bits_expr.tag, _cast_enum_to_bits_expr_1 + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + connect io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_2 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_4: UInt<1> + match io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_4, UInt<1>(1) + wire _cast_enum_to_bits_expr_5: UInt<1> + match _bundle_literal_expr_3.tag: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_5, UInt<1>(1) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_4, _cast_enum_to_bits_expr_5), eq(io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect parent_out.opt_opt_unit_flip, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + wire _bundle_literal_expr_4: Ty2 + connect _bundle_literal_expr_4.tag, {|HdlNone, HdlSome|}(HdlSome) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + connect _array_literal_expr[0], _bundle_literal_expr_4 + connect _array_literal_expr[1], _bundle_literal_expr_2 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_3, __enum_structural_eq_4) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_6: UInt<1> + match io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_6, UInt<1>(1) + wire _cast_enum_to_bits_expr_7: UInt<1> + match _array_literal_expr[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_7, UInt<1>(1) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_6, _cast_enum_to_bits_expr_7), eq(io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_8: UInt<1> + match io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_8, UInt<1>(1) + wire _cast_enum_to_bits_expr_9: UInt<1> + match _array_literal_expr[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_9, UInt<1>(1) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_8, _cast_enum_to_bits_expr_9), eq(io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect parent_out.array_opt_bool_flip, and(_bundle_structural_eq_3, _bundle_structural_eq_4) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty3 + connect _bundle_literal_expr_5.`0`, _bundle_literal_expr_2 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_5, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_10: UInt<1> + match io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_10, UInt<1>(1) + wire _cast_enum_to_bits_expr_11: UInt<1> + match _bundle_literal_expr_5.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_11, UInt<1>(1) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_10, _cast_enum_to_bits_expr_11), eq(io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect parent_out.struct_opt_bool_flip, and(_bundle_structural_eq_5, eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_bundle_expr: Ty1 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.tag, bits(UInt<1>(0h0), 0, 0) + wire _cast_bits_to_enum_expr: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.tag, 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr.tag, _cast_bits_to_enum_expr + connect _cast_bits_to_bundle_expr_flattened.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr.body, _cast_bits_to_bundle_expr_flattened.body + connect io_zeros.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_12: UInt<1> + match io_zeros.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_12, UInt<1>(1) + wire _cast_enum_to_bits_expr_13: UInt<1> + match _cast_bits_to_bundle_expr.tag: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_13, UInt<1>(1) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_12, _cast_enum_to_bits_expr_13), eq(io_zeros.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit_flip, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_1: Ty2 + wire _cast_bits_to_bundle_expr_flattened_1: Ty8 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(UInt<2>(0h0), 0, 0) + wire _cast_bits_to_enum_expr_1: Ty0 + 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(UInt<2>(0h0), 1, 1) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect io_zeros.opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_7 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_14: UInt<1> + match io_zeros.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_14, UInt<1>(1) + wire _cast_enum_to_bits_expr_15: UInt<1> + match _cast_bits_to_bundle_expr_1.tag: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_15, UInt<1>(1) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_14, _cast_enum_to_bits_expr_15), eq(io_zeros.opt_bool_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_16: UInt<1> + match io_zeros.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_16, UInt<1>(1) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_15), eq(io_zeros.opt_opt_unit_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_opt_unit_flip, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_2: Ty2 + wire _cast_bits_to_bundle_expr_flattened_2: Ty8 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(_cast_bits_to_array_expr_flattened[0], 0, 0) + wire _cast_bits_to_enum_expr_2: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(_cast_bits_to_array_expr_flattened[0], 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + connect _cast_bits_to_array_expr[0], _cast_bits_to_bundle_expr_2 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_bundle_expr_3: Ty2 + wire _cast_bits_to_bundle_expr_flattened_3: Ty8 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(_cast_bits_to_array_expr_flattened[1], 0, 0) + wire _cast_bits_to_enum_expr_3: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 + connect _cast_bits_to_bundle_expr_flattened_3.body, bits(_cast_bits_to_array_expr_flattened[1], 1, 1) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect _cast_bits_to_array_expr[1], _cast_bits_to_bundle_expr_3 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_9, __enum_structural_eq_10) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_17: UInt<1> + match io_zeros.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_17, UInt<1>(1) + wire _cast_enum_to_bits_expr_18: UInt<1> + match _cast_bits_to_array_expr[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_18, UInt<1>(1) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_17, _cast_enum_to_bits_expr_18), eq(io_zeros.array_opt_bool_flip[0].body, _cast_bits_to_array_expr[0].body)) + wire _cast_enum_to_bits_expr_19: UInt<1> + match io_zeros.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_19, UInt<1>(1) + wire _cast_enum_to_bits_expr_20: UInt<1> + match _cast_bits_to_array_expr[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_20, UInt<1>(1) + wire _bundle_structural_eq_10: UInt<1> + connect _bundle_structural_eq_10, and(eq(_cast_enum_to_bits_expr_19, _cast_enum_to_bits_expr_20), eq(io_zeros.array_opt_bool_flip[1].body, _cast_bits_to_array_expr[1].body)) + connect parent_zeros_out.array_opt_bool_flip, and(_bundle_structural_eq_9, _bundle_structural_eq_10) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_4: Ty3 + wire _cast_bits_to_bundle_expr_flattened_4: Ty9 + connect _cast_bits_to_bundle_expr_flattened_4.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_5: Ty2 + wire _cast_bits_to_bundle_expr_flattened_5: Ty8 + connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 0, 0) + wire _cast_bits_to_enum_expr_4: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.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_5.tag, _cast_bits_to_enum_expr_4 + connect _cast_bits_to_bundle_expr_flattened_5.body, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body + connect _cast_bits_to_bundle_expr_4.`0`, _cast_bits_to_bundle_expr_5 + connect _cast_bits_to_bundle_expr_flattened_4.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_4.`1`, _cast_bits_to_bundle_expr_flattened_4.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_4 @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_11, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_21, UInt<1>(1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_bundle_expr_4.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_22, UInt<1>(1) + wire _bundle_structural_eq_11: UInt<1> + connect _bundle_structural_eq_11, and(eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22), eq(io_zeros.struct_opt_bool_flip.`0`.body, _cast_bits_to_bundle_expr_4.`0`.body)) + connect parent_zeros_out.struct_opt_bool_flip, and(_bundle_structural_eq_11, eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_alternating.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_23, UInt<1>(1) + wire _bundle_structural_eq_12: UInt<1> + connect _bundle_structural_eq_12, and(eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_13), eq(io_alternating.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit_flip, _bundle_structural_eq_12 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_6: Ty2 + wire _cast_bits_to_bundle_expr_flattened_6: Ty8 + connect _cast_bits_to_bundle_expr_flattened_6.tag, bits(UInt<2>(0h2), 0, 0) + wire _cast_bits_to_enum_expr_5: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_6.tag, 0)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_6.tag, _cast_bits_to_enum_expr_5 + connect _cast_bits_to_bundle_expr_flattened_6.body, bits(UInt<2>(0h2), 1, 1) + connect _cast_bits_to_bundle_expr_6.body, _cast_bits_to_bundle_expr_flattened_6.body + connect io_alternating.opt_bool_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_14 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_15 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_16 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_bundle_expr_7: Ty2 + wire _cast_bits_to_bundle_expr_flattened_7: Ty8 + connect _cast_bits_to_bundle_expr_flattened_7.tag, bits(_cast_bits_to_array_expr_flattened_1[0], 0, 0) + wire _cast_bits_to_enum_expr_6: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_7.tag, 0)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_7.tag, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened_7.body, bits(_cast_bits_to_array_expr_flattened_1[0], 1, 1) + connect _cast_bits_to_bundle_expr_7.body, _cast_bits_to_bundle_expr_flattened_7.body + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_bundle_expr_7 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_bundle_expr_8: Ty2 + wire _cast_bits_to_bundle_expr_flattened_8: Ty8 + connect _cast_bits_to_bundle_expr_flattened_8.tag, bits(_cast_bits_to_array_expr_flattened_1[1], 0, 0) + wire _cast_bits_to_enum_expr_7: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_8.tag, 0)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_8.tag, _cast_bits_to_enum_expr_7 + connect _cast_bits_to_bundle_expr_flattened_8.body, bits(_cast_bits_to_array_expr_flattened_1[1], 1, 1) + connect _cast_bits_to_bundle_expr_8.body, _cast_bits_to_bundle_expr_flattened_8.body + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_bundle_expr_8 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_17, __enum_structural_eq_18) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_19, __enum_structural_eq_20) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_9: Ty3 + wire _cast_bits_to_bundle_expr_flattened_9: Ty9 + connect _cast_bits_to_bundle_expr_flattened_9.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_bundle_expr_10: Ty2 + wire _cast_bits_to_bundle_expr_flattened_10: Ty8 + connect _cast_bits_to_bundle_expr_flattened_10.tag, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 0, 0) + wire _cast_bits_to_enum_expr_8: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_10.tag, 0)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_10.tag, _cast_bits_to_enum_expr_8 + connect _cast_bits_to_bundle_expr_flattened_10.body, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_10.body, _cast_bits_to_bundle_expr_flattened_10.body + connect _cast_bits_to_bundle_expr_9.`0`, _cast_bits_to_bundle_expr_10 + connect _cast_bits_to_bundle_expr_flattened_9.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_9.`1`, _cast_bits_to_bundle_expr_flattened_9.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_9 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_21, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_22, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit, __enum_structural_eq_23 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_24: UInt<1> + match extern_child.io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_24, UInt<1>(1) + wire _bundle_structural_eq_13: UInt<1> + connect _bundle_structural_eq_13, and(eq(_cast_enum_to_bits_expr_24, _cast_enum_to_bits_expr_1), eq(extern_child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit_flip, _bundle_structural_eq_13 @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_24 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_25: UInt<1> + match extern_child.io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_25, UInt<1>(1) + wire _bundle_structural_eq_14: UInt<1> + connect _bundle_structural_eq_14, and(eq(_cast_enum_to_bits_expr_25, _cast_enum_to_bits_expr_3), eq(extern_child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect extern_child_out.opt_bool_flip, _bundle_structural_eq_14 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_26: UInt<1> + match extern_child.io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_26, UInt<1>(1) + wire _bundle_structural_eq_15: UInt<1> + connect _bundle_structural_eq_15, and(eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_5), eq(extern_child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect extern_child_out.opt_opt_unit_flip, _bundle_structural_eq_15 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_26, __enum_structural_eq_27) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_27: UInt<1> + match extern_child.io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_27, UInt<1>(1) + wire _bundle_structural_eq_16: UInt<1> + connect _bundle_structural_eq_16, and(eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_7), eq(extern_child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_28: UInt<1> + match extern_child.io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_28, UInt<1>(1) + wire _bundle_structural_eq_17: UInt<1> + connect _bundle_structural_eq_17, and(eq(_cast_enum_to_bits_expr_28, _cast_enum_to_bits_expr_9), eq(extern_child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect extern_child_out.array_opt_bool_flip, and(_bundle_structural_eq_16, _bundle_structural_eq_17) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_28, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_29: UInt<1> + match extern_child.io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_29, UInt<1>(1) + wire _bundle_structural_eq_18: UInt<1> + connect _bundle_structural_eq_18, and(eq(_cast_enum_to_bits_expr_29, _cast_enum_to_bits_expr_11), eq(extern_child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect extern_child_out.struct_opt_bool_flip, and(_bundle_structural_eq_18, eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_30: UInt<1> + match child.io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_30, UInt<1>(1) + wire _bundle_structural_eq_19: UInt<1> + connect _bundle_structural_eq_19, and(eq(_cast_enum_to_bits_expr_30, _cast_enum_to_bits_expr_1), eq(child.io.opt_unit.body, _bundle_literal_expr.body)) + connect child_out.opt_unit, _bundle_structural_eq_19 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_31: UInt<1> + match child.io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_31, UInt<1>(1) + wire _bundle_structural_eq_20: UInt<1> + connect _bundle_structural_eq_20, and(eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_1), eq(child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect child_out.opt_unit_flip, _bundle_structural_eq_20 @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_32: UInt<1> + match child.io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_32, UInt<1>(1) + wire _bundle_structural_eq_21: UInt<1> + connect _bundle_structural_eq_21, and(eq(_cast_enum_to_bits_expr_32, _cast_enum_to_bits_expr_3), eq(child.io.opt_bool.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool, _bundle_structural_eq_21 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_33: UInt<1> + match child.io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_33, UInt<1>(1) + wire _bundle_structural_eq_22: UInt<1> + connect _bundle_structural_eq_22, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_3), eq(child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool_flip, _bundle_structural_eq_22 @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_34: UInt<1> + match child.io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_34, UInt<1>(1) + wire _bundle_structural_eq_23: UInt<1> + connect _bundle_structural_eq_23, and(eq(_cast_enum_to_bits_expr_34, _cast_enum_to_bits_expr_5), eq(child.io.opt_opt_unit.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit, _bundle_structural_eq_23 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_35: UInt<1> + match child.io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_35, UInt<1>(1) + wire _bundle_structural_eq_24: UInt<1> + connect _bundle_structural_eq_24, and(eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_5), eq(child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit_flip, _bundle_structural_eq_24 @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_36: UInt<1> + match child.io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_36, UInt<1>(1) + wire _bundle_structural_eq_25: UInt<1> + connect _bundle_structural_eq_25, and(eq(_cast_enum_to_bits_expr_36, _cast_enum_to_bits_expr_7), eq(child.io.array_opt_bool[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_37: UInt<1> + match child.io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_37, UInt<1>(1) + wire _bundle_structural_eq_26: UInt<1> + connect _bundle_structural_eq_26, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_9), eq(child.io.array_opt_bool[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool, and(_bundle_structural_eq_25, _bundle_structural_eq_26) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_38: UInt<1> + match child.io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_38, UInt<1>(1) + wire _bundle_structural_eq_27: UInt<1> + connect _bundle_structural_eq_27, and(eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_7), eq(child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_39: UInt<1> + match child.io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_39, UInt<1>(1) + wire _bundle_structural_eq_28: UInt<1> + connect _bundle_structural_eq_28, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_9), eq(child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool_flip, and(_bundle_structural_eq_27, _bundle_structural_eq_28) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_40: UInt<1> + match child.io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_40, UInt<1>(1) + wire _bundle_structural_eq_29: UInt<1> + connect _bundle_structural_eq_29, and(eq(_cast_enum_to_bits_expr_40, _cast_enum_to_bits_expr_11), eq(child.io.struct_opt_bool.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool, and(_bundle_structural_eq_29, eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_41: UInt<1> + match child.io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_41, UInt<1>(1) + wire _bundle_structural_eq_30: UInt<1> + connect _bundle_structural_eq_30, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_11), eq(child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool_flip, and(_bundle_structural_eq_30, eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_42, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1] + match io.opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_11: Ty6 + invalidate _cast_bits_to_bundle_expr_11 + wire _cast_bits_to_bundle_expr_12: Ty6 + invalidate _cast_bits_to_bundle_expr_12 + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_43: UInt<1> + match io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_43, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_3): @[module-XXXXXXXXXX.rs 1:1] + match io.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_1, eq(bits(io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_44: UInt<1> + match io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_44, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_5): @[module-XXXXXXXXXX.rs 1:1] + match io.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_13: Ty1 + wire _cast_bits_to_bundle_expr_flattened_11: Ty7 + connect _cast_bits_to_bundle_expr_flattened_11.tag, bits(bits(io.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_9: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_11.tag, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_13.tag, _cast_bits_to_enum_expr_9 + connect _cast_bits_to_bundle_expr_flattened_11.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_13.body, _cast_bits_to_bundle_expr_flattened_11.body + wire _cast_bits_to_bundle_expr_14: Ty1 + wire _cast_bits_to_bundle_expr_flattened_12: Ty7 + connect _cast_bits_to_bundle_expr_flattened_12.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_10: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_12.tag, 0)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_14.tag, _cast_bits_to_enum_expr_10 + connect _cast_bits_to_bundle_expr_flattened_12.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_14.body, _cast_bits_to_bundle_expr_flattened_12.body + wire _cast_enum_to_bits_expr_45: UInt<1> + match _cast_bits_to_bundle_expr_13.tag: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_45, UInt<1>(1) + wire _cast_enum_to_bits_expr_46: UInt<1> + match _cast_bits_to_bundle_expr_14.tag: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_46, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_45, _cast_enum_to_bits_expr_46): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_13.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_15: Ty6 + invalidate _cast_bits_to_bundle_expr_15 + wire _cast_bits_to_bundle_expr_16: Ty6 + invalidate _cast_bits_to_bundle_expr_16 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_47: UInt<1> + match io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_47, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_7): @[module-XXXXXXXXXX.rs 1:1] + match io.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_3, eq(bits(io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_48: UInt<1> + match io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_48, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_48, _cast_enum_to_bits_expr_9): @[module-XXXXXXXXXX.rs 1:1] + match io.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_4, eq(bits(io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_49: UInt<1> + match io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_49, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_49, _cast_enum_to_bits_expr_11): @[module-XXXXXXXXXX.rs 1:1] + match io.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_5, eq(bits(io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_50: UInt<1> + match io_zeros.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_50, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_50, _cast_enum_to_bits_expr_13): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_17: Ty6 + invalidate _cast_bits_to_bundle_expr_17 + wire _cast_bits_to_bundle_expr_18: Ty6 + invalidate _cast_bits_to_bundle_expr_18 + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_51: UInt<1> + match io_zeros.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_51, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_15): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_7, eq(bits(io_zeros.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_1.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_52: UInt<1> + match io_zeros.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_52, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_52, _cast_enum_to_bits_expr_15): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_30: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, __enum_structural_eq_30 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_30, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_19: Ty1 + wire _cast_bits_to_bundle_expr_flattened_13: Ty7 + connect _cast_bits_to_bundle_expr_flattened_13.tag, bits(bits(io_zeros.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_11: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_13.tag, 0)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_19.tag, _cast_bits_to_enum_expr_11 + connect _cast_bits_to_bundle_expr_flattened_13.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_19.body, _cast_bits_to_bundle_expr_flattened_13.body + wire _cast_bits_to_bundle_expr_20: Ty1 + wire _cast_bits_to_bundle_expr_flattened_14: Ty7 + connect _cast_bits_to_bundle_expr_flattened_14.tag, bits(bits(_cast_bits_to_bundle_expr_1.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_12: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_14.tag, 0)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_20.tag, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_14.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_20.body, _cast_bits_to_bundle_expr_flattened_14.body + wire _cast_enum_to_bits_expr_53: UInt<1> + match _cast_bits_to_bundle_expr_19.tag: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_53, UInt<1>(1) + wire _cast_enum_to_bits_expr_54: UInt<1> + match _cast_bits_to_bundle_expr_20.tag: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_54, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_54): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_19.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_21: Ty6 + invalidate _cast_bits_to_bundle_expr_21 + wire _cast_bits_to_bundle_expr_22: Ty6 + invalidate _cast_bits_to_bundle_expr_22 + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_55: UInt<1> + match io_zeros.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_55, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_18): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_9, eq(bits(io_zeros.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_56: UInt<1> + match io_zeros.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_56, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_56, _cast_enum_to_bits_expr_20): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_10, eq(bits(io_zeros.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_57: UInt<1> + match io_zeros.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_57, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_22): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_11, eq(bits(io_zeros.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_4.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_58: UInt<1> + match io_alternating.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_58, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_13): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_23: Ty6 + invalidate _cast_bits_to_bundle_expr_23 + wire _cast_bits_to_bundle_expr_24: Ty6 + invalidate _cast_bits_to_bundle_expr_24 + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_59: UInt<1> + match io_alternating.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_59, UInt<1>(1) + wire _cast_enum_to_bits_expr_60: UInt<1> + match _cast_bits_to_bundle_expr_6.tag: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_60, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_60): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_13, eq(bits(io_alternating.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_61: UInt<1> + match io_alternating.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_61, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_61, _cast_enum_to_bits_expr_60): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_bool_flip.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_14, eq(bits(io_alternating.opt_bool_flip.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match io_alternating.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_62, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_60): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_31: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, __enum_structural_eq_31 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_31, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_25: Ty1 + wire _cast_bits_to_bundle_expr_flattened_15: Ty7 + connect _cast_bits_to_bundle_expr_flattened_15.tag, bits(bits(io_alternating.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_13: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_15.tag, 0)): + connect _cast_bits_to_enum_expr_13, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_13, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_25.tag, _cast_bits_to_enum_expr_13 + connect _cast_bits_to_bundle_expr_flattened_15.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_25.body, _cast_bits_to_bundle_expr_flattened_15.body + wire _cast_bits_to_bundle_expr_26: Ty1 + wire _cast_bits_to_bundle_expr_flattened_16: Ty7 + connect _cast_bits_to_bundle_expr_flattened_16.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_14: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_16.tag, 0)): + connect _cast_bits_to_enum_expr_14, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_14, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_26.tag, _cast_bits_to_enum_expr_14 + connect _cast_bits_to_bundle_expr_flattened_16.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_26.body, _cast_bits_to_bundle_expr_flattened_16.body + wire _cast_enum_to_bits_expr_63: UInt<1> + match _cast_bits_to_bundle_expr_25.tag: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_63, UInt<1>(1) + wire _cast_enum_to_bits_expr_64: UInt<1> + match _cast_bits_to_bundle_expr_26.tag: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_64, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_64): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_25.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_27: Ty6 + invalidate _cast_bits_to_bundle_expr_27 + wire _cast_bits_to_bundle_expr_28: Ty6 + invalidate _cast_bits_to_bundle_expr_28 + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_65: UInt<1> + match io_alternating.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_65, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_65, _cast_enum_to_bits_expr_60): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_opt_unit_flip.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_32: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, __enum_structural_eq_32 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_32, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_29: Ty1 + wire _cast_bits_to_bundle_expr_flattened_17: Ty7 + connect _cast_bits_to_bundle_expr_flattened_17.tag, bits(bits(io_alternating.opt_opt_unit_flip.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_15: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_17.tag, 0)): + connect _cast_bits_to_enum_expr_15, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_15, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_29.tag, _cast_bits_to_enum_expr_15 + connect _cast_bits_to_bundle_expr_flattened_17.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_29.body, _cast_bits_to_bundle_expr_flattened_17.body + wire _cast_bits_to_bundle_expr_30: Ty1 + wire _cast_bits_to_bundle_expr_flattened_18: Ty7 + connect _cast_bits_to_bundle_expr_flattened_18.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_16: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_18.tag, 0)): + connect _cast_bits_to_enum_expr_16, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_16, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_30.tag, _cast_bits_to_enum_expr_16 + connect _cast_bits_to_bundle_expr_flattened_18.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_30.body, _cast_bits_to_bundle_expr_flattened_18.body + wire _cast_enum_to_bits_expr_66: UInt<1> + match _cast_bits_to_bundle_expr_29.tag: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_66, UInt<1>(1) + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_bits_to_bundle_expr_30.tag: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_67, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_67): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_29.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_31: Ty6 + invalidate _cast_bits_to_bundle_expr_31 + wire _cast_bits_to_bundle_expr_32: Ty6 + invalidate _cast_bits_to_bundle_expr_32 + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_68: UInt<1> + match io_alternating.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_68, UInt<1>(1) + wire _cast_enum_to_bits_expr_69: UInt<1> + match _cast_bits_to_array_expr_1[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_69, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_68, _cast_enum_to_bits_expr_69): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_17, eq(bits(io_alternating.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_70: UInt<1> + match io_alternating.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_70, UInt<1>(1) + wire _cast_enum_to_bits_expr_71: UInt<1> + match _cast_bits_to_array_expr_1[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_71, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_70, _cast_enum_to_bits_expr_71): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_18, eq(bits(io_alternating.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_72: UInt<1> + match io_alternating.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_72, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_72, _cast_enum_to_bits_expr_69): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool_flip[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_19, eq(bits(io_alternating.array_opt_bool_flip[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_73: UInt<1> + match io_alternating.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_73, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_71): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool_flip[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_20, eq(bits(io_alternating.array_opt_bool_flip[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_74: UInt<1> + match io_alternating.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_74, UInt<1>(1) + wire _cast_enum_to_bits_expr_75: UInt<1> + match _cast_bits_to_bundle_expr_9.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_75, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_75): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_21, eq(bits(io_alternating.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_76: UInt<1> + match io_alternating.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_76, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_76, _cast_enum_to_bits_expr_75): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.struct_opt_bool_flip.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_22, eq(bits(io_alternating.struct_opt_bool_flip.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match extern_child.io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_77, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_33: Ty6 + invalidate _cast_bits_to_bundle_expr_33 + wire _cast_bits_to_bundle_expr_34: Ty6 + invalidate _cast_bits_to_bundle_expr_34 + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_78: UInt<1> + match extern_child.io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_78, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_3): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_24, eq(bits(extern_child.io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_79: UInt<1> + match extern_child.io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_79, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_5): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_33: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, __enum_structural_eq_33 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_33, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_35: Ty1 + wire _cast_bits_to_bundle_expr_flattened_19: Ty7 + connect _cast_bits_to_bundle_expr_flattened_19.tag, bits(bits(extern_child.io.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_17: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_19.tag, 0)): + connect _cast_bits_to_enum_expr_17, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_17, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_35.tag, _cast_bits_to_enum_expr_17 + connect _cast_bits_to_bundle_expr_flattened_19.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_35.body, _cast_bits_to_bundle_expr_flattened_19.body + wire _cast_bits_to_bundle_expr_36: Ty1 + wire _cast_bits_to_bundle_expr_flattened_20: Ty7 + connect _cast_bits_to_bundle_expr_flattened_20.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_18: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_20.tag, 0)): + connect _cast_bits_to_enum_expr_18, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_18, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_36.tag, _cast_bits_to_enum_expr_18 + connect _cast_bits_to_bundle_expr_flattened_20.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_36.body, _cast_bits_to_bundle_expr_flattened_20.body + wire _cast_enum_to_bits_expr_80: UInt<1> + match _cast_bits_to_bundle_expr_35.tag: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_80, UInt<1>(1) + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_bits_to_bundle_expr_36.tag: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_81, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_81): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_35.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_37: Ty6 + invalidate _cast_bits_to_bundle_expr_37 + wire _cast_bits_to_bundle_expr_38: Ty6 + invalidate _cast_bits_to_bundle_expr_38 + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_82: UInt<1> + match extern_child.io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_82, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_7): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_26, eq(bits(extern_child.io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_83: UInt<1> + match extern_child.io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_83, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_83, _cast_enum_to_bits_expr_9): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_27, eq(bits(extern_child.io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_84: UInt<1> + match extern_child.io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_84, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_11): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_28, eq(bits(extern_child.io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty4 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty4 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_bundle_of_uints = simplify_enums(m, SimplifyEnumsKind::ReplaceWithBundleOfUInts).unwrap(); + dbg!(m_bundle_of_uints); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_bundle_of_uints => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {tag: UInt<1>, body: UInt<0>} + type Ty1 = {tag: UInt<1>, body: UInt<1>} + type Ty2 = {`0`: Ty1, `1`: UInt<1>} + type Ty3 = {flip opt_unit_flip: Ty0, opt_unit: Ty0, flip opt_bool_flip: Ty1, opt_bool: Ty1, flip opt_opt_unit_flip: Ty1, opt_opt_unit: Ty1, flip array_opt_bool_flip: Ty1[2], array_opt_bool: Ty1[2], flip struct_opt_bool_flip: Ty2, struct_opt_bool: Ty2} + type Ty4 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty5 = {} + type Ty6 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty7 = {io: Ty3} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty3 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty3 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty3 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty4 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty4 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty4 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty4 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty4 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + connect _bundle_literal_expr.tag, UInt<1>(0h1) + wire _bundle_literal_expr_1: Ty5 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + connect io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit, __enum_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit_flip, _bundle_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty1 + connect _bundle_literal_expr_2.tag, UInt<1>(0h1) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + connect io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect parent_out.opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty1 + connect _bundle_literal_expr_3.tag, UInt<1>(0h1) + wire _cast_bundle_to_bits_expr: Ty0 + connect _cast_bundle_to_bits_expr.tag, _bundle_literal_expr.tag + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + connect io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_2 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect parent_out.opt_opt_unit_flip, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty1[2] + wire _bundle_literal_expr_4: Ty1 + connect _bundle_literal_expr_4.tag, UInt<1>(0h1) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + connect _array_literal_expr[0], _bundle_literal_expr_4 + connect _array_literal_expr[1], _bundle_literal_expr_2 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_3, __enum_structural_eq_4) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect parent_out.array_opt_bool_flip, and(_bundle_structural_eq_3, _bundle_structural_eq_4) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty2 + connect _bundle_literal_expr_5.`0`, _bundle_literal_expr_2 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_5, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect parent_out.struct_opt_bool_flip, and(_bundle_structural_eq_5, eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_bundle_expr: Ty0 + wire _cast_bits_to_bundle_expr_flattened: Ty0 + connect _cast_bits_to_bundle_expr_flattened.tag, bits(UInt<1>(0h0), 0, 0) + connect _cast_bits_to_bundle_expr.tag, _cast_bits_to_bundle_expr_flattened.tag + connect _cast_bits_to_bundle_expr_flattened.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr.body, _cast_bits_to_bundle_expr_flattened.body + connect io_zeros.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(io_zeros.opt_unit_flip.tag, _cast_bits_to_bundle_expr.tag), eq(io_zeros.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit_flip, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_1: Ty1 + wire _cast_bits_to_bundle_expr_flattened_1: Ty1 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(UInt<2>(0h0), 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(UInt<2>(0h0), 1, 1) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect io_zeros.opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_7 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(io_zeros.opt_bool_flip.tag, _cast_bits_to_bundle_expr_1.tag), eq(io_zeros.opt_bool_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_8 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(io_zeros.opt_opt_unit_flip.tag, _cast_bits_to_bundle_expr_1.tag), eq(io_zeros.opt_opt_unit_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_opt_unit_flip, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty1[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_2: Ty1 + wire _cast_bits_to_bundle_expr_flattened_2: Ty1 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(_cast_bits_to_array_expr_flattened[0], 0, 0) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(_cast_bits_to_array_expr_flattened[0], 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + connect _cast_bits_to_array_expr[0], _cast_bits_to_bundle_expr_2 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_bundle_expr_3: Ty1 + wire _cast_bits_to_bundle_expr_flattened_3: Ty1 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(_cast_bits_to_array_expr_flattened[1], 0, 0) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag + connect _cast_bits_to_bundle_expr_flattened_3.body, bits(_cast_bits_to_array_expr_flattened[1], 1, 1) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect _cast_bits_to_array_expr[1], _cast_bits_to_bundle_expr_3 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_9, __enum_structural_eq_10) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(io_zeros.array_opt_bool_flip[0].tag, _cast_bits_to_array_expr[0].tag), eq(io_zeros.array_opt_bool_flip[0].body, _cast_bits_to_array_expr[0].body)) + wire _bundle_structural_eq_10: UInt<1> + connect _bundle_structural_eq_10, and(eq(io_zeros.array_opt_bool_flip[1].tag, _cast_bits_to_array_expr[1].tag), eq(io_zeros.array_opt_bool_flip[1].body, _cast_bits_to_array_expr[1].body)) + connect parent_zeros_out.array_opt_bool_flip, and(_bundle_structural_eq_9, _bundle_structural_eq_10) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_4: Ty2 + wire _cast_bits_to_bundle_expr_flattened_4: Ty6 + connect _cast_bits_to_bundle_expr_flattened_4.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_5: Ty1 + wire _cast_bits_to_bundle_expr_flattened_5: Ty1 + connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 0, 0) + connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag + connect _cast_bits_to_bundle_expr_flattened_5.body, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body + connect _cast_bits_to_bundle_expr_4.`0`, _cast_bits_to_bundle_expr_5 + connect _cast_bits_to_bundle_expr_flattened_4.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_4.`1`, _cast_bits_to_bundle_expr_flattened_4.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_4 @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_11, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_11: UInt<1> + connect _bundle_structural_eq_11, and(eq(io_zeros.struct_opt_bool_flip.`0`.tag, _cast_bits_to_bundle_expr_4.`0`.tag), eq(io_zeros.struct_opt_bool_flip.`0`.body, _cast_bits_to_bundle_expr_4.`0`.body)) + connect parent_zeros_out.struct_opt_bool_flip, and(_bundle_structural_eq_11, eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_12: UInt<1> + connect _bundle_structural_eq_12, and(eq(io_alternating.opt_unit_flip.tag, _cast_bits_to_bundle_expr.tag), eq(io_alternating.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit_flip, _bundle_structural_eq_12 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_6: Ty1 + wire _cast_bits_to_bundle_expr_flattened_6: Ty1 + connect _cast_bits_to_bundle_expr_flattened_6.tag, bits(UInt<2>(0h2), 0, 0) + connect _cast_bits_to_bundle_expr_6.tag, _cast_bits_to_bundle_expr_flattened_6.tag + connect _cast_bits_to_bundle_expr_flattened_6.body, bits(UInt<2>(0h2), 1, 1) + connect _cast_bits_to_bundle_expr_6.body, _cast_bits_to_bundle_expr_flattened_6.body + connect io_alternating.opt_bool_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_14 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_15 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_16 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty1[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_bundle_expr_7: Ty1 + wire _cast_bits_to_bundle_expr_flattened_7: Ty1 + connect _cast_bits_to_bundle_expr_flattened_7.tag, bits(_cast_bits_to_array_expr_flattened_1[0], 0, 0) + connect _cast_bits_to_bundle_expr_7.tag, _cast_bits_to_bundle_expr_flattened_7.tag + connect _cast_bits_to_bundle_expr_flattened_7.body, bits(_cast_bits_to_array_expr_flattened_1[0], 1, 1) + connect _cast_bits_to_bundle_expr_7.body, _cast_bits_to_bundle_expr_flattened_7.body + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_bundle_expr_7 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_bundle_expr_8: Ty1 + wire _cast_bits_to_bundle_expr_flattened_8: Ty1 + connect _cast_bits_to_bundle_expr_flattened_8.tag, bits(_cast_bits_to_array_expr_flattened_1[1], 0, 0) + connect _cast_bits_to_bundle_expr_8.tag, _cast_bits_to_bundle_expr_flattened_8.tag + connect _cast_bits_to_bundle_expr_flattened_8.body, bits(_cast_bits_to_array_expr_flattened_1[1], 1, 1) + connect _cast_bits_to_bundle_expr_8.body, _cast_bits_to_bundle_expr_flattened_8.body + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_bundle_expr_8 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_17, __enum_structural_eq_18) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_19, __enum_structural_eq_20) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_9: Ty2 + wire _cast_bits_to_bundle_expr_flattened_9: Ty6 + connect _cast_bits_to_bundle_expr_flattened_9.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_bundle_expr_10: Ty1 + wire _cast_bits_to_bundle_expr_flattened_10: Ty1 + connect _cast_bits_to_bundle_expr_flattened_10.tag, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 0, 0) + connect _cast_bits_to_bundle_expr_10.tag, _cast_bits_to_bundle_expr_flattened_10.tag + connect _cast_bits_to_bundle_expr_flattened_10.body, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_10.body, _cast_bits_to_bundle_expr_flattened_10.body + connect _cast_bits_to_bundle_expr_9.`0`, _cast_bits_to_bundle_expr_10 + connect _cast_bits_to_bundle_expr_flattened_9.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_9.`1`, _cast_bits_to_bundle_expr_flattened_9.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_9 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_21, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_22, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit, __enum_structural_eq_23 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_13: UInt<1> + connect _bundle_structural_eq_13, and(eq(extern_child.io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(extern_child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit_flip, _bundle_structural_eq_13 @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_24 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_14: UInt<1> + connect _bundle_structural_eq_14, and(eq(extern_child.io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(extern_child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect extern_child_out.opt_bool_flip, _bundle_structural_eq_14 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_15: UInt<1> + connect _bundle_structural_eq_15, and(eq(extern_child.io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(extern_child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect extern_child_out.opt_opt_unit_flip, _bundle_structural_eq_15 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_26, __enum_structural_eq_27) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_16: UInt<1> + connect _bundle_structural_eq_16, and(eq(extern_child.io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(extern_child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_17: UInt<1> + connect _bundle_structural_eq_17, and(eq(extern_child.io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(extern_child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect extern_child_out.array_opt_bool_flip, and(_bundle_structural_eq_16, _bundle_structural_eq_17) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_28, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_18: UInt<1> + connect _bundle_structural_eq_18, and(eq(extern_child.io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(extern_child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect extern_child_out.struct_opt_bool_flip, and(_bundle_structural_eq_18, eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_19: UInt<1> + connect _bundle_structural_eq_19, and(eq(child.io.opt_unit.tag, _bundle_literal_expr.tag), eq(child.io.opt_unit.body, _bundle_literal_expr.body)) + connect child_out.opt_unit, _bundle_structural_eq_19 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_20: UInt<1> + connect _bundle_structural_eq_20, and(eq(child.io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect child_out.opt_unit_flip, _bundle_structural_eq_20 @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_21: UInt<1> + connect _bundle_structural_eq_21, and(eq(child.io.opt_bool.tag, _bundle_literal_expr_2.tag), eq(child.io.opt_bool.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool, _bundle_structural_eq_21 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_22: UInt<1> + connect _bundle_structural_eq_22, and(eq(child.io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool_flip, _bundle_structural_eq_22 @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_23: UInt<1> + connect _bundle_structural_eq_23, and(eq(child.io.opt_opt_unit.tag, _bundle_literal_expr_3.tag), eq(child.io.opt_opt_unit.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit, _bundle_structural_eq_23 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_24: UInt<1> + connect _bundle_structural_eq_24, and(eq(child.io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit_flip, _bundle_structural_eq_24 @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_25: UInt<1> + connect _bundle_structural_eq_25, and(eq(child.io.array_opt_bool[0].tag, _array_literal_expr[0].tag), eq(child.io.array_opt_bool[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_26: UInt<1> + connect _bundle_structural_eq_26, and(eq(child.io.array_opt_bool[1].tag, _array_literal_expr[1].tag), eq(child.io.array_opt_bool[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool, and(_bundle_structural_eq_25, _bundle_structural_eq_26) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_27: UInt<1> + connect _bundle_structural_eq_27, and(eq(child.io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_28: UInt<1> + connect _bundle_structural_eq_28, and(eq(child.io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool_flip, and(_bundle_structural_eq_27, _bundle_structural_eq_28) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_29: UInt<1> + connect _bundle_structural_eq_29, and(eq(child.io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(child.io.struct_opt_bool.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool, and(_bundle_structural_eq_29, eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_30: UInt<1> + connect _bundle_structural_eq_30, and(eq(child.io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool_flip, and(_bundle_structural_eq_30, eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_unit.tag, _bundle_literal_expr.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_11: Ty5 + invalidate _cast_bits_to_bundle_expr_11 + wire _cast_bits_to_bundle_expr_12: Ty5 + invalidate _cast_bits_to_bundle_expr_12 + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_bool.tag, _bundle_literal_expr_2.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_1, eq(bits(io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_opt_unit.tag, _bundle_literal_expr_3.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_13: Ty0 + wire _cast_bits_to_bundle_expr_flattened_11: Ty0 + connect _cast_bits_to_bundle_expr_flattened_11.tag, bits(bits(io.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_13.tag, _cast_bits_to_bundle_expr_flattened_11.tag + connect _cast_bits_to_bundle_expr_flattened_11.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_13.body, _cast_bits_to_bundle_expr_flattened_11.body + wire _cast_bits_to_bundle_expr_14: Ty0 + wire _cast_bits_to_bundle_expr_flattened_12: Ty0 + connect _cast_bits_to_bundle_expr_flattened_12.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_14.tag, _cast_bits_to_bundle_expr_flattened_12.tag + connect _cast_bits_to_bundle_expr_flattened_12.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_14.body, _cast_bits_to_bundle_expr_flattened_12.body + when eq(_cast_bits_to_bundle_expr_13.tag, _cast_bits_to_bundle_expr_14.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_13.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_15: Ty5 + invalidate _cast_bits_to_bundle_expr_15 + wire _cast_bits_to_bundle_expr_16: Ty5 + invalidate _cast_bits_to_bundle_expr_16 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[0].tag, _array_literal_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_3, eq(bits(io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[1].tag, _array_literal_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_4, eq(bits(io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_5, eq(bits(io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_unit.tag, _cast_bits_to_bundle_expr.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_17: Ty5 + invalidate _cast_bits_to_bundle_expr_17 + wire _cast_bits_to_bundle_expr_18: Ty5 + invalidate _cast_bits_to_bundle_expr_18 + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_bool.tag, _cast_bits_to_bundle_expr_1.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_7, eq(bits(io_zeros.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_1.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_opt_unit.tag, _cast_bits_to_bundle_expr_1.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_30: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, __enum_structural_eq_30 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_30, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_19: Ty0 + wire _cast_bits_to_bundle_expr_flattened_13: Ty0 + connect _cast_bits_to_bundle_expr_flattened_13.tag, bits(bits(io_zeros.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_19.tag, _cast_bits_to_bundle_expr_flattened_13.tag + connect _cast_bits_to_bundle_expr_flattened_13.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_19.body, _cast_bits_to_bundle_expr_flattened_13.body + wire _cast_bits_to_bundle_expr_20: Ty0 + wire _cast_bits_to_bundle_expr_flattened_14: Ty0 + connect _cast_bits_to_bundle_expr_flattened_14.tag, bits(bits(_cast_bits_to_bundle_expr_1.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_20.tag, _cast_bits_to_bundle_expr_flattened_14.tag + connect _cast_bits_to_bundle_expr_flattened_14.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_20.body, _cast_bits_to_bundle_expr_flattened_14.body + when eq(_cast_bits_to_bundle_expr_19.tag, _cast_bits_to_bundle_expr_20.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_19.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_21: Ty5 + invalidate _cast_bits_to_bundle_expr_21 + wire _cast_bits_to_bundle_expr_22: Ty5 + invalidate _cast_bits_to_bundle_expr_22 + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[0].tag, _cast_bits_to_array_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_9, eq(bits(io_zeros.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[1].tag, _cast_bits_to_array_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_10, eq(bits(io_zeros.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.struct_opt_bool.`0`.tag, _cast_bits_to_bundle_expr_4.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_11, eq(bits(io_zeros.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_4.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_unit.tag, _cast_bits_to_bundle_expr.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_23: Ty5 + invalidate _cast_bits_to_bundle_expr_23 + wire _cast_bits_to_bundle_expr_24: Ty5 + invalidate _cast_bits_to_bundle_expr_24 + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_13, eq(bits(io_alternating.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool_flip.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool_flip.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_14, eq(bits(io_alternating.opt_bool_flip.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_31: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, __enum_structural_eq_31 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_31, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_25: Ty0 + wire _cast_bits_to_bundle_expr_flattened_15: Ty0 + connect _cast_bits_to_bundle_expr_flattened_15.tag, bits(bits(io_alternating.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_25.tag, _cast_bits_to_bundle_expr_flattened_15.tag + connect _cast_bits_to_bundle_expr_flattened_15.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_25.body, _cast_bits_to_bundle_expr_flattened_15.body + wire _cast_bits_to_bundle_expr_26: Ty0 + wire _cast_bits_to_bundle_expr_flattened_16: Ty0 + connect _cast_bits_to_bundle_expr_flattened_16.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_26.tag, _cast_bits_to_bundle_expr_flattened_16.tag + connect _cast_bits_to_bundle_expr_flattened_16.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_26.body, _cast_bits_to_bundle_expr_flattened_16.body + when eq(_cast_bits_to_bundle_expr_25.tag, _cast_bits_to_bundle_expr_26.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_25.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_27: Ty5 + invalidate _cast_bits_to_bundle_expr_27 + wire _cast_bits_to_bundle_expr_28: Ty5 + invalidate _cast_bits_to_bundle_expr_28 + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit_flip.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit_flip.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_32: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, __enum_structural_eq_32 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_32, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_29: Ty0 + wire _cast_bits_to_bundle_expr_flattened_17: Ty0 + connect _cast_bits_to_bundle_expr_flattened_17.tag, bits(bits(io_alternating.opt_opt_unit_flip.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_29.tag, _cast_bits_to_bundle_expr_flattened_17.tag + connect _cast_bits_to_bundle_expr_flattened_17.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_29.body, _cast_bits_to_bundle_expr_flattened_17.body + wire _cast_bits_to_bundle_expr_30: Ty0 + wire _cast_bits_to_bundle_expr_flattened_18: Ty0 + connect _cast_bits_to_bundle_expr_flattened_18.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_30.tag, _cast_bits_to_bundle_expr_flattened_18.tag + connect _cast_bits_to_bundle_expr_flattened_18.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_30.body, _cast_bits_to_bundle_expr_flattened_18.body + when eq(_cast_bits_to_bundle_expr_29.tag, _cast_bits_to_bundle_expr_30.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_29.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_31: Ty5 + invalidate _cast_bits_to_bundle_expr_31 + wire _cast_bits_to_bundle_expr_32: Ty5 + invalidate _cast_bits_to_bundle_expr_32 + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[0].tag, _cast_bits_to_array_expr_1[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_17, eq(bits(io_alternating.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[1].tag, _cast_bits_to_array_expr_1[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_18, eq(bits(io_alternating.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[0].tag, _cast_bits_to_array_expr_1[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_19, eq(bits(io_alternating.array_opt_bool_flip[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[1].tag, _cast_bits_to_array_expr_1[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_20, eq(bits(io_alternating.array_opt_bool_flip[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool.`0`.tag, _cast_bits_to_bundle_expr_9.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_21, eq(bits(io_alternating.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool_flip.`0`.tag, _cast_bits_to_bundle_expr_9.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool_flip.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_22, eq(bits(io_alternating.struct_opt_bool_flip.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_unit.tag, _bundle_literal_expr.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_33: Ty5 + invalidate _cast_bits_to_bundle_expr_33 + wire _cast_bits_to_bundle_expr_34: Ty5 + invalidate _cast_bits_to_bundle_expr_34 + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_bool.tag, _bundle_literal_expr_2.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_24, eq(bits(extern_child.io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_opt_unit.tag, _bundle_literal_expr_3.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_33: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, __enum_structural_eq_33 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_33, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_35: Ty0 + wire _cast_bits_to_bundle_expr_flattened_19: Ty0 + connect _cast_bits_to_bundle_expr_flattened_19.tag, bits(bits(extern_child.io.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_35.tag, _cast_bits_to_bundle_expr_flattened_19.tag + connect _cast_bits_to_bundle_expr_flattened_19.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_35.body, _cast_bits_to_bundle_expr_flattened_19.body + wire _cast_bits_to_bundle_expr_36: Ty0 + wire _cast_bits_to_bundle_expr_flattened_20: Ty0 + connect _cast_bits_to_bundle_expr_flattened_20.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_36.tag, _cast_bits_to_bundle_expr_flattened_20.tag + connect _cast_bits_to_bundle_expr_flattened_20.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_36.body, _cast_bits_to_bundle_expr_flattened_20.body + when eq(_cast_bits_to_bundle_expr_35.tag, _cast_bits_to_bundle_expr_36.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_35.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_37: Ty5 + invalidate _cast_bits_to_bundle_expr_37 + wire _cast_bits_to_bundle_expr_38: Ty5 + invalidate _cast_bits_to_bundle_expr_38 + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[0].tag, _array_literal_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_26, eq(bits(extern_child.io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[1].tag, _array_literal_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_27, eq(bits(extern_child.io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_28, eq(bits(extern_child.io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty3 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty3 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_uints = simplify_enums(m, SimplifyEnumsKind::ReplaceWithUInt).unwrap(); + dbg!(m_uints); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_uints => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty1 = {flip opt_unit_flip: UInt<1>, opt_unit: UInt<1>, flip opt_bool_flip: UInt<2>, opt_bool: UInt<2>, flip opt_opt_unit_flip: UInt<2>, opt_opt_unit: UInt<2>, flip array_opt_bool_flip: UInt<2>[2], array_opt_bool: UInt<2>[2], flip struct_opt_bool_flip: Ty0, struct_opt_bool: Ty0} + type Ty2 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty3 = {tag: UInt<1>, body: UInt<0>} + type Ty4 = {} + type Ty5 = {tag: UInt<1>, body: UInt<1>} + type Ty6 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty7 = {io: Ty1} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty1 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty1 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty1 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty2 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty2 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty2 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty2 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty2 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty3 + connect _bundle_literal_expr.tag, UInt<1>(0h1) + wire _bundle_literal_expr_1: Ty4 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + wire _cast_bundle_to_bits_expr: Ty3 + connect _cast_bundle_to_bits_expr.tag, _bundle_literal_expr.tag + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit, __enum_structural_eq @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit_flip, eq(io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty5 + connect _bundle_literal_expr_2.tag, UInt<1>(0h1) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + wire _cast_bundle_to_bits_expr_1: Ty5 + connect _cast_bundle_to_bits_expr_1.tag, _bundle_literal_expr_2.tag + connect _cast_bundle_to_bits_expr_1.body, _bundle_literal_expr_2.body + wire _cast_to_bits_expr_1: UInt<2> + connect _cast_to_bits_expr_1, cat(_cast_bundle_to_bits_expr_1.body, _cast_bundle_to_bits_expr_1.tag) + connect io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool_flip, eq(io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty5 + connect _bundle_literal_expr_3.tag, UInt<1>(0h1) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + wire _cast_bundle_to_bits_expr_2: Ty5 + connect _cast_bundle_to_bits_expr_2.tag, _bundle_literal_expr_3.tag + connect _cast_bundle_to_bits_expr_2.body, _bundle_literal_expr_3.body + wire _cast_to_bits_expr_2: UInt<2> + connect _cast_to_bits_expr_2, cat(_cast_bundle_to_bits_expr_2.body, _cast_bundle_to_bits_expr_2.tag) + connect io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_2 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit_flip, eq(io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: UInt<2>[2] + wire _bundle_literal_expr_4: Ty5 + connect _bundle_literal_expr_4.tag, UInt<1>(0h1) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + wire _cast_bundle_to_bits_expr_3: Ty5 + connect _cast_bundle_to_bits_expr_3.tag, _bundle_literal_expr_4.tag + connect _cast_bundle_to_bits_expr_3.body, _bundle_literal_expr_4.body + wire _cast_to_bits_expr_3: UInt<2> + connect _cast_to_bits_expr_3, cat(_cast_bundle_to_bits_expr_3.body, _cast_bundle_to_bits_expr_3.tag) + connect _array_literal_expr[0], _cast_to_bits_expr_3 + connect _array_literal_expr[1], _cast_to_bits_expr_1 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_3, __enum_structural_eq_4) @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool_flip, and(eq(io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty0 + connect _bundle_literal_expr_5.`0`, _cast_to_bits_expr_1 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_5, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool_flip, and(eq(io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_zeros.opt_unit_flip, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit_flip, eq(io_zeros.opt_unit_flip, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect io_zeros.opt_bool_flip, UInt<2>(0h0) @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_7 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool_flip, eq(io_zeros.opt_bool_flip, UInt<2>(0h0)) @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, UInt<2>(0h0) @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_8 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit_flip, eq(io_zeros.opt_opt_unit_flip, UInt<2>(0h0)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: UInt<2>[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_9, __enum_structural_eq_10) @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool_flip, and(eq(io_zeros.array_opt_bool_flip[0], _cast_bits_to_array_expr[0]), eq(io_zeros.array_opt_bool_flip[1], _cast_bits_to_array_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr: Ty0 + wire _cast_bits_to_bundle_expr_flattened: Ty6 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + connect _cast_bits_to_bundle_expr.`0`, _cast_bits_to_bundle_expr_flattened.`0` + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_11, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool_flip, and(eq(io_zeros.struct_opt_bool_flip.`0`, _cast_bits_to_bundle_expr.`0`), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit_flip, eq(io_alternating.opt_unit_flip, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect io_alternating.opt_bool_flip, UInt<2>(0h2) @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_14 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, UInt<2>(0h2) @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_15 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_16 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: UInt<2>[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_17, __enum_structural_eq_18) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_19, __enum_structural_eq_20) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty0 + wire _cast_bits_to_bundle_expr_flattened_1: Ty6 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_bundle_expr_flattened_1.`0` + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_21, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_22, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit, __enum_structural_eq_23 @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit_flip, eq(extern_child.io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_24 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool_flip, eq(extern_child.io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit_flip, eq(extern_child.io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_26, __enum_structural_eq_27) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool_flip, and(eq(extern_child.io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(extern_child.io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_28, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool_flip, and(eq(extern_child.io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect child_out.opt_unit, eq(child.io.opt_unit, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect child_out.opt_unit_flip, eq(child.io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect child_out.opt_bool, eq(child.io.opt_bool, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect child_out.opt_bool_flip, eq(child.io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect child_out.opt_opt_unit, eq(child.io.opt_opt_unit, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect child_out.opt_opt_unit_flip, eq(child.io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect child_out.array_opt_bool, and(eq(child.io.array_opt_bool[0], _array_literal_expr[0]), eq(child.io.array_opt_bool[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect child_out.array_opt_bool_flip, and(eq(child.io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(child.io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect child_out.struct_opt_bool, and(eq(child.io.struct_opt_bool.`0`, _bundle_literal_expr_5.`0`), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child_out.struct_opt_bool_flip, and(eq(child.io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_unit, 0, 0), bits(_cast_to_bits_expr, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_2: Ty4 + invalidate _cast_bits_to_bundle_expr_2 + wire _cast_bits_to_bundle_expr_3: Ty4 + invalidate _cast_bits_to_bundle_expr_3 + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_bool, 0, 0), bits(_cast_to_bits_expr_1, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_1, eq(bits(bits(io.opt_bool, 1, 1), 0, 0), bits(bits(_cast_to_bits_expr_1, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_opt_unit, 0, 0), bits(_cast_to_bits_expr_2, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(_cast_to_bits_expr_2, 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_4: Ty4 + invalidate _cast_bits_to_bundle_expr_4 + wire _cast_bits_to_bundle_expr_5: Ty4 + invalidate _cast_bits_to_bundle_expr_5 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[0], 0, 0), bits(_array_literal_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_3, eq(bits(bits(io.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_array_literal_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[1], 0, 0), bits(_array_literal_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_4, eq(bits(bits(io.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_array_literal_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.struct_opt_bool.`0`, 0, 0), bits(_bundle_literal_expr_5.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_5, eq(bits(bits(io.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_bundle_literal_expr_5.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_unit, 0, 0), bits(UInt<1>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_6: Ty4 + invalidate _cast_bits_to_bundle_expr_6 + wire _cast_bits_to_bundle_expr_7: Ty4 + invalidate _cast_bits_to_bundle_expr_7 + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_bool, 0, 0), bits(UInt<2>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_7, eq(bits(bits(io_zeros.opt_bool, 1, 1), 0, 0), bits(bits(UInt<2>(0h0), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_opt_unit, 0, 0), bits(UInt<2>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_30: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, __enum_structural_eq_30 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_30, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_zeros.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h0), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_zeros.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_8: Ty4 + invalidate _cast_bits_to_bundle_expr_8 + wire _cast_bits_to_bundle_expr_9: Ty4 + invalidate _cast_bits_to_bundle_expr_9 + connect __enum_structural_eq_30, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[0], 0, 0), bits(_cast_bits_to_array_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_9, eq(bits(bits(io_zeros.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[1], 0, 0), bits(_cast_bits_to_array_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_10, eq(bits(bits(io_zeros.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.struct_opt_bool.`0`, 0, 0), bits(_cast_bits_to_bundle_expr.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_11, eq(bits(bits(io_zeros.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_unit, 0, 0), bits(UInt<1>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_10: Ty4 + invalidate _cast_bits_to_bundle_expr_10 + wire _cast_bits_to_bundle_expr_11: Ty4 + invalidate _cast_bits_to_bundle_expr_11 + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_13, eq(bits(bits(io_alternating.opt_bool, 1, 1), 0, 0), bits(bits(UInt<2>(0h2), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool_flip, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool_flip, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_14, eq(bits(bits(io_alternating.opt_bool_flip, 1, 1), 0, 0), bits(bits(UInt<2>(0h2), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_31: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, __enum_structural_eq_31 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_31, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h2), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_12: Ty4 + invalidate _cast_bits_to_bundle_expr_12 + wire _cast_bits_to_bundle_expr_13: Ty4 + invalidate _cast_bits_to_bundle_expr_13 + connect __enum_structural_eq_31, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit_flip, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit_flip, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_32: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, __enum_structural_eq_32 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_32, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit_flip, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h2), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit_flip, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_14: Ty4 + invalidate _cast_bits_to_bundle_expr_14 + wire _cast_bits_to_bundle_expr_15: Ty4 + invalidate _cast_bits_to_bundle_expr_15 + connect __enum_structural_eq_32, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[0], 0, 0), bits(_cast_bits_to_array_expr_1[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_17, eq(bits(bits(io_alternating.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[1], 0, 0), bits(_cast_bits_to_array_expr_1[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_18, eq(bits(bits(io_alternating.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[0], 0, 0), bits(_cast_bits_to_array_expr_1[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_19, eq(bits(bits(io_alternating.array_opt_bool_flip[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[1], 0, 0), bits(_cast_bits_to_array_expr_1[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_20, eq(bits(bits(io_alternating.array_opt_bool_flip[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool.`0`, 0, 0), bits(_cast_bits_to_bundle_expr_1.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_21, eq(bits(bits(io_alternating.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr_1.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool_flip.`0`, 0, 0), bits(_cast_bits_to_bundle_expr_1.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool_flip.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_22, eq(bits(bits(io_alternating.struct_opt_bool_flip.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr_1.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_unit, 0, 0), bits(_cast_to_bits_expr, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_16: Ty4 + invalidate _cast_bits_to_bundle_expr_16 + wire _cast_bits_to_bundle_expr_17: Ty4 + invalidate _cast_bits_to_bundle_expr_17 + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_bool, 0, 0), bits(_cast_to_bits_expr_1, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_24, eq(bits(bits(extern_child.io.opt_bool, 1, 1), 0, 0), bits(bits(_cast_to_bits_expr_1, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_opt_unit, 0, 0), bits(_cast_to_bits_expr_2, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_33: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, __enum_structural_eq_33 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_33, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(extern_child.io.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(_cast_to_bits_expr_2, 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(extern_child.io.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_18: Ty4 + invalidate _cast_bits_to_bundle_expr_18 + wire _cast_bits_to_bundle_expr_19: Ty4 + invalidate _cast_bits_to_bundle_expr_19 + connect __enum_structural_eq_33, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[0], 0, 0), bits(_array_literal_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_26, eq(bits(bits(extern_child.io.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_array_literal_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[1], 0, 0), bits(_array_literal_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_27, eq(bits(bits(extern_child.io.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_array_literal_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.struct_opt_bool.`0`, 0, 0), bits(_bundle_literal_expr_5.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_28, eq(bits(bits(extern_child.io.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_bundle_literal_expr_5.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty1 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty1 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; +} diff --git a/crates/fayalite/tests/expected/my_test.md b/crates/fayalite/tests/expected/my_test.md new file mode 100644 index 0000000..a3b52ae --- /dev/null +++ b/crates/fayalite/tests/expected/my_test.md @@ -0,0 +1,6 @@ + + +`my_test.vcd` is used in the doctest of `fayalite::testing::checked_vcd_output` diff --git a/crates/fayalite/tests/expected/my_test.vcd b/crates/fayalite/tests/expected/my_test.vcd new file mode 100644 index 0000000..3df1caf --- /dev/null +++ b/crates/fayalite/tests/expected/my_test.vcd @@ -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/ diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index 9dc0107..7d12810 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -709,44 +709,35 @@ circuit check_enum_cmp_eq: input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - match lhs: @[module-XXXXXXXXXX.rs 5:1] + wire _cast_enum_to_bits_expr: UInt<10> + match lhs: A: - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - B(_match_arm_value): - skip - C(_match_arm_value_1): - skip - B(_match_arm_value_2): - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B(_match_arm_value_3): - connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1] - C(_match_arm_value_4): - skip - C(_match_arm_value_5): - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B(_match_arm_value_6): - skip - C(_match_arm_value_7): - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0]) - connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1]) - connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + connect _cast_enum_to_bits_expr, UInt<10>(0) + B(_cast_enum_to_bits_expr_B): + connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10) + C(_cast_enum_to_bits_expr_C): + wire _cast_array_to_bits_expr: UInt<1>[3] + connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0] + connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1] + connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2] + wire _cast_to_bits_expr: UInt<3> + connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) + connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10) + wire _cast_enum_to_bits_expr_1: UInt<10> + match rhs: + A: + connect _cast_enum_to_bits_expr_1, UInt<10>(0) + B(_cast_enum_to_bits_expr_B_1): + connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10) + C(_cast_enum_to_bits_expr_C_1): + wire _cast_array_to_bits_expr_1: UInt<1>[3] + connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0] + connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1] + connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2] + wire _cast_to_bits_expr_1: UInt<3> + connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0])) + connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10) + connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -764,92 +755,53 @@ circuit check_enum_cmp_eq: input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - match lhs.tag: @[module-XXXXXXXXXX.rs 5:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr: UInt<2> + match lhs.tag: A: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - B: - skip - C: - skip + connect _cast_enum_to_bits_expr, UInt<2>(0) B: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B: - connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - C: - skip + connect _cast_enum_to_bits_expr, UInt<2>(1) C: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B: - skip - C: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + connect _cast_enum_to_bits_expr, UInt<2>(2) + wire _cast_enum_to_bits_expr_1: UInt<2> + match rhs.tag: + A: + connect _cast_enum_to_bits_expr_1, UInt<2>(0) + B: + connect _cast_enum_to_bits_expr_1, UInt<2>(1) + C: + connect _cast_enum_to_bits_expr_1, UInt<2>(2) + when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1] + match lhs.tag: @[module-XXXXXXXXXX.rs 1:1] + A: + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + B: + connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + C: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -866,83 +818,36 @@ circuit check_enum_cmp_eq: input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -958,83 +863,36 @@ circuit check_enum_cmp_eq: input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1] input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; } @@ -3779,20 +3637,176 @@ circuit check_formal: %[[ input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1] input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1] input pred3: UInt<1> @[module-XXXXXXXXXX.rs 8:1] - inst formal_reset of formal_reset @[formal.rs 185:24] + inst formal_reset of formal_reset @[builtin 1:1] assert(clk, pred1, and(en1, not(formal_reset.rst)), "en check 1") @[module-XXXXXXXXXX.rs 9:1] - inst formal_reset_1 of formal_reset @[formal.rs 185:24] - assume(clk, pred2, and(en2, not(formal_reset_1.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1] - inst formal_reset_2 of formal_reset @[formal.rs 185:24] - cover(clk, pred3, and(en3, not(formal_reset_2.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1] - inst formal_reset_3 of formal_reset @[formal.rs 185:24] - assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset_3.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1] - inst formal_reset_4 of formal_reset @[formal.rs 185:24] - assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset_4.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1] - inst formal_reset_5 of formal_reset @[formal.rs 185:24] - cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset_5.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1] - extmodule formal_reset: @[formal.rs 169:5] - output rst: UInt<1> @[formal.rs 172:32] + assume(clk, pred2, and(en2, not(formal_reset.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1] + cover(clk, pred3, and(en3, not(formal_reset.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1] + assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1] + assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1] + cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1] + extmodule formal_reset: @[builtin 1:1] + output rst: UInt<1> @[builtin 1:1] + defname = __fayalite_formal_reset +"#, + }; +} + +#[hdl_module(outline_generated)] +pub fn check_formal_input() { + #[hdl] + let bool_in: Bool = m.input(); + #[hdl] + let bool_out: Bool = m.output(); + #[hdl] + let any_const_out1: Bool = m.output(); + #[hdl] + let any_const_out2: UInt<16> = m.output(); + #[hdl] + let any_const_out3: SInt<12> = m.output(); + #[hdl] + let any_seq_out: UInt<10> = m.output(); + #[hdl] + let all_const_out: UInt<10> = m.output(); + #[hdl] + let all_seq_out: UInt<10> = m.output(); + + #[hdl] + let bool_reg = reg_builder() + .clock_domain( + #[hdl] + ClockDomain { + clk: formal_global_clock(), + rst: formal_reset(), + }, + ) + .reset(false); + + connect(bool_reg, bool_in); + connect(bool_out, bool_reg); + connect(any_const_out1, any_const(StaticType::TYPE)); + connect(any_const_out2, any_const(StaticType::TYPE)); + connect(any_const_out3, any_const(StaticType::TYPE)); + connect(any_seq_out, any_seq(StaticType::TYPE)); + connect(all_const_out, all_const(StaticType::TYPE)); + connect(all_seq_out, all_seq(StaticType::TYPE)); +} + +#[test] +fn test_formal_input() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = check_formal_input(); + dbg!(m); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + "/test/check_formal_input.fir": r#"FIRRTL version 3.2.0 +circuit check_formal_input: %[[ + { + "class": "firrtl.AttributeAnnotation", + "description": "gclk", + "target": "~check_formal_input|check_formal_input>formal_global_clock" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>formal_global_clock" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "anyconst", + "target": "~check_formal_input|check_formal_input>any_const" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>any_const" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "anyconst", + "target": "~check_formal_input|check_formal_input>any_const_1" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>any_const_1" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "anyconst", + "target": "~check_formal_input|check_formal_input>any_const_2" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>any_const_2" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "anyseq", + "target": "~check_formal_input|check_formal_input>any_seq" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>any_seq" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "allconst", + "target": "~check_formal_input|check_formal_input>all_const" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>all_const" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "allseq", + "target": "~check_formal_input|check_formal_input>all_seq" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_formal_input|check_formal_input>all_seq" + }, + { + "class": "firrtl.transforms.BlackBoxInlineAnno", + "name": "fayalite_formal_reset.v", + "text": "module __fayalite_formal_reset(output rst);\n assign rst = $initstate;\nendmodule\n", + "target": "~check_formal_input|formal_reset" + } +]] + type Ty0 = {clk: Clock, rst: UInt<1>} + type Ty1 = {rst: UInt<1>} + module check_formal_input: @[module-XXXXXXXXXX.rs 1:1] + input bool_in: UInt<1> @[module-XXXXXXXXXX.rs 2:1] + output bool_out: UInt<1> @[module-XXXXXXXXXX.rs 3:1] + output any_const_out1: UInt<1> @[module-XXXXXXXXXX.rs 4:1] + output any_const_out2: UInt<16> @[module-XXXXXXXXXX.rs 5:1] + output any_const_out3: SInt<12> @[module-XXXXXXXXXX.rs 6:1] + output any_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 7:1] + output all_const_out: UInt<10> @[module-XXXXXXXXXX.rs 8:1] + output all_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 9:1] + wire _bundle_literal_expr_1: Ty0 + connect _bundle_literal_expr_1.clk, asClock(UInt<1>(0h0)) + connect _bundle_literal_expr_1.rst, UInt<1>(0h0) + reg formal_global_clock: UInt<1>, _bundle_literal_expr_1.clk @[builtin 1:1] + inst formal_reset of formal_reset @[builtin 1:1] + reg any_const: UInt<1>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 13:1] + reg any_const_1: UInt<16>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 15:1] + reg any_const_2: SInt<12>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 17:1] + reg any_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 19:1] + reg all_const: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 21:1] + reg all_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 23:1] + wire _bundle_literal_expr: Ty0 + connect _bundle_literal_expr.clk, asClock(formal_global_clock) + connect _bundle_literal_expr.rst, formal_reset.rst + regreset bool_reg: UInt<1>, _bundle_literal_expr.clk, _bundle_literal_expr.rst, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 10:1] + connect bool_reg, bool_in @[module-XXXXXXXXXX.rs 11:1] + connect bool_out, bool_reg @[module-XXXXXXXXXX.rs 12:1] + connect any_const_out1, any_const @[module-XXXXXXXXXX.rs 14:1] + connect any_const_out2, any_const_1 @[module-XXXXXXXXXX.rs 16:1] + connect any_const_out3, any_const_2 @[module-XXXXXXXXXX.rs 18:1] + connect any_seq_out, any_seq @[module-XXXXXXXXXX.rs 20:1] + connect all_const_out, all_const @[module-XXXXXXXXXX.rs 22:1] + connect all_seq_out, all_seq @[module-XXXXXXXXXX.rs 24:1] + extmodule formal_reset: @[builtin 1:1] + output rst: UInt<1> @[builtin 1:1] defname = __fayalite_formal_reset "#, }; @@ -3925,21 +3939,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1] HdlSome: wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_1: Ty5 - wire _cast_bits_to_bundle_expr_flattened_1: Ty6 - connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0) - wire _cast_bits_to_enum_expr_1: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)): - connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone) - else: - connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1 - connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1) - connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body ; connect different types: ; lhs: SInt<1> ; rhs: SInt<2> - connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] + connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_2: Ty4 connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome) connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2) @@ -3961,18 +3964,18 @@ circuit check_enum_connect_any: connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1] C: wire __connect_variant_body_3: Ty8 @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_2: Ty8 - wire _cast_bits_to_bundle_expr_flattened_2: Ty9 - connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0) - wire _cast_bits_to_enum_expr_2: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): - connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_1: Ty8 + wire _cast_bits_to_bundle_expr_flattened_1: Ty9 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_1: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 - connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body - connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1] + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1 + connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_4: Ty1 connect _bundle_literal_expr_4.tag, {|A, B, C|}(C) wire _cast_bundle_to_bits_expr_1: Ty9 @@ -4001,18 +4004,18 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1] B: wire __connect_variant_body_5: Ty5 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_3: Ty4 - wire _cast_bits_to_bundle_expr_flattened_3: Ty7 - connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0) - wire _cast_bits_to_enum_expr_3: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): - connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_2: Ty7 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0) + wire _cast_bits_to_enum_expr_2: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 - connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body - match _cast_bits_to_bundle_expr_3.tag: @[module-XXXXXXXXXX.rs 9:1] + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + match _cast_bits_to_bundle_expr_2.tag: @[module-XXXXXXXXXX.rs 9:1] HdlNone: wire _bundle_literal_expr_6: Ty5 connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone) @@ -4020,21 +4023,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1] HdlSome: wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_4: Ty4 - wire _cast_bits_to_bundle_expr_flattened_4: Ty7 - connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0) - wire _cast_bits_to_enum_expr_4: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_4.tag, 0)): - connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlNone) - else: - connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_enum_expr_4 - connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body ; connect different types: ; lhs: SInt<2> ; rhs: SInt<1> - connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] + connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_7: Ty5 connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome) connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6) @@ -4056,18 +4048,18 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1] C: wire __connect_variant_body_7: Ty8 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_5: Ty8 - wire _cast_bits_to_bundle_expr_flattened_5: Ty9 - connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0) - wire _cast_bits_to_enum_expr_5: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)): - connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_3: Ty8 + wire _cast_bits_to_bundle_expr_flattened_3: Ty9 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_3: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_5 - connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body - connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1] + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 + connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_9: Ty2 connect _bundle_literal_expr_9.tag, {|A, B, C|}(C) wire _cast_bundle_to_bits_expr_3: Ty9 @@ -4134,16 +4126,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1] else: wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_1: Ty3 - wire _cast_bits_to_bundle_expr_flattened_1: Ty3 - connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0) - connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag - connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1) - connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body ; connect different types: ; lhs: SInt<1> ; rhs: SInt<2> - connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] + connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_2: Ty2 connect _bundle_literal_expr_2.tag, UInt<1>(0h1) connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2) @@ -4159,13 +4145,13 @@ circuit check_enum_connect_any: connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1] else: wire __connect_variant_body_3: Ty4 @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_2: Ty4 - wire _cast_bits_to_bundle_expr_flattened_2: Ty4 - connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0) - connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag - connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body - connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty4 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag + connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_4: Ty0 connect _bundle_literal_expr_4.tag, UInt<2>(0h2) wire _cast_bundle_to_bits_expr_1: Ty4 @@ -4187,29 +4173,23 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1] else when eq(i1.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 9:1] wire __connect_variant_body_5: Ty3 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_3: Ty2 - wire _cast_bits_to_bundle_expr_flattened_3: Ty2 - connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0) - connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag - connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body - when eq(_cast_bits_to_bundle_expr_3.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1] + wire _cast_bits_to_bundle_expr_2: Ty2 + wire _cast_bits_to_bundle_expr_flattened_2: Ty2 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + when eq(_cast_bits_to_bundle_expr_2.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_6: Ty3 connect _bundle_literal_expr_6.tag, UInt<1>(0h0) connect _bundle_literal_expr_6.body, UInt<2>(0h0) connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1] else: wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_4: Ty2 - wire _cast_bits_to_bundle_expr_flattened_4: Ty2 - connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0) - connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_bundle_expr_flattened_4.tag - connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body ; connect different types: ; lhs: SInt<2> ; rhs: SInt<1> - connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] + connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_7: Ty3 connect _bundle_literal_expr_7.tag, UInt<1>(0h1) connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6) @@ -4225,13 +4205,13 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1] else: wire __connect_variant_body_7: Ty4 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_5: Ty4 - wire _cast_bits_to_bundle_expr_flattened_5: Ty4 - connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0) - connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag - connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body - connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1] + wire _cast_bits_to_bundle_expr_3: Ty4 + wire _cast_bits_to_bundle_expr_flattened_3: Ty4 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag + connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_9: Ty1 connect _bundle_literal_expr_9.tag, UInt<2>(0h2) wire _cast_bundle_to_bits_expr_3: Ty4 @@ -4883,34 +4863,20 @@ circuit check_struct_cmp_eq: 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_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1] - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`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 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] + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(tuple_lhs.`0`, tuple_rhs.`0`), eq(tuple_lhs.`1`, tuple_rhs.`1`)) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(_bundle_structural_eq, eq(tuple_lhs.`2`, tuple_rhs.`2`)) + connect tuple_cmp_eq, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 5:1] + connect tuple_cmp_ne, not(_bundle_structural_eq_1) @[module-XXXXXXXXXX.rs 7:1] + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) + connect test_struct_cmp_eq, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 11:1] + connect test_struct_cmp_ne, not(_bundle_structural_eq_2) @[module-XXXXXXXXXX.rs 13:1] connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1] - connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1] + connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19:1] connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1] - connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1] + connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1] ", }; } diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 80ae4c2..343b87b 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -5,6 +5,7 @@ use bitvec::{order::Lsb0, view::BitView}; use fayalite::{ assert_export_firrtl, firrtl::ExportOptions, + formal::FormalInputKind, memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask}, module::{ instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc, @@ -16,7 +17,12 @@ use fayalite::{ ty::SimValueDebug, util::{RcWriter, ready_valid::queue}, }; -use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc}; +use std::{ + collections::BTreeMap, + num::NonZeroUsize, + panic::{AssertUnwindSafe, catch_unwind, resume_unwind}, + rc::Rc, +}; #[hdl_module(outline_generated)] pub fn connect_const() { @@ -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::>::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::>::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::() { + 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> = m.input(); + #[hdl] + let b: HdlOption> = 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!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt index 271ec3c..e6a0a7a 100644 --- a/crates/fayalite/tests/sim/expected/array_rw.txt +++ b/crates/fayalite/tests/sim/expected/array_rw.txt @@ -419,6 +419,7 @@ Simulation { }, pc: 38, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -497,6 +498,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1759,5 +1761,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt index 74c03a4..8013727 100644 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt @@ -76,6 +76,7 @@ Simulation { }, pc: 5, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -101,6 +102,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -186,5 +188,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/connect_const.txt b/crates/fayalite/tests/sim/expected/connect_const.txt index 8193fc5..9ec4a83 100644 --- a/crates/fayalite/tests/sim/expected/connect_const.txt +++ b/crates/fayalite/tests/sim/expected/connect_const.txt @@ -54,6 +54,7 @@ Simulation { }, pc: 2, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -77,6 +78,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -138,5 +140,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/connect_const_reset.txt b/crates/fayalite/tests/sim/expected/connect_const_reset.txt index 5a64923..dfbc3b9 100644 --- a/crates/fayalite/tests/sim/expected/connect_const_reset.txt +++ b/crates/fayalite/tests/sim/expected/connect_const_reset.txt @@ -80,6 +80,7 @@ Simulation { }, pc: 5, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -106,6 +107,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -206,5 +208,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/counter_async.txt b/crates/fayalite/tests/sim/expected/counter_async.txt index 20d27ac..c05ed80 100644 --- a/crates/fayalite/tests/sim/expected/counter_async.txt +++ b/crates/fayalite/tests/sim/expected/counter_async.txt @@ -180,6 +180,7 @@ Simulation { }, pc: 19, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -216,6 +217,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -385,5 +387,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/counter_sync.txt b/crates/fayalite/tests/sim/expected/counter_sync.txt index baa08e7..5834877 100644 --- a/crates/fayalite/tests/sim/expected/counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/counter_sync.txt @@ -162,6 +162,7 @@ Simulation { }, pc: 16, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -197,6 +198,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -366,5 +368,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt index 76338e8..3a4c115 100644 --- a/crates/fayalite/tests/sim/expected/duplicate_names.txt +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -72,6 +72,7 @@ Simulation { }, pc: 4, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -97,6 +98,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [], uninitialized_ios: {}, @@ -169,5 +171,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt b/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt index 6b5af1c..e7c6a85 100644 --- a/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt +++ b/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt @@ -409,6 +409,7 @@ Simulation { }, pc: 45, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -465,6 +466,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -745,5 +747,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt index d2da2d9..a539f96 100644 --- a/crates/fayalite/tests/sim/expected/enums.txt +++ b/crates/fayalite/tests/sim/expected/enums.txt @@ -1184,6 +1184,7 @@ Simulation { }, pc: 133, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -1324,6 +1325,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1955,5 +1957,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt index 48a3af5..fa003d3 100644 --- a/crates/fayalite/tests/sim/expected/extern_module.txt +++ b/crates/fayalite/tests/sim/expected/extern_module.txt @@ -44,6 +44,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -67,6 +68,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -261,5 +263,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module2.txt b/crates/fayalite/tests/sim/expected/extern_module2.txt index d488666..8c03792 100644 --- a/crates/fayalite/tests/sim/expected/extern_module2.txt +++ b/crates/fayalite/tests/sim/expected/extern_module2.txt @@ -48,6 +48,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -72,6 +73,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -416,5 +418,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/last_connect.txt b/crates/fayalite/tests/sim/expected/last_connect.txt index c5d1341..e62c0b7 100644 --- a/crates/fayalite/tests/sim/expected/last_connect.txt +++ b/crates/fayalite/tests/sim/expected/last_connect.txt @@ -407,6 +407,7 @@ Simulation { }, pc: 44, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -464,6 +465,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -705,5 +707,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/many_memories.txt b/crates/fayalite/tests/sim/expected/many_memories.txt index 0d1a6db..1cb60ae 100644 --- a/crates/fayalite/tests/sim/expected/many_memories.txt +++ b/crates/fayalite/tests/sim/expected/many_memories.txt @@ -2728,6 +2728,7 @@ Simulation { }, pc: 256, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -3183,6 +3184,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -7927,5 +7929,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/memories.txt b/crates/fayalite/tests/sim/expected/memories.txt index c96da4f..f2f4fb6 100644 --- a/crates/fayalite/tests/sim/expected/memories.txt +++ b/crates/fayalite/tests/sim/expected/memories.txt @@ -494,6 +494,7 @@ Simulation { }, pc: 41, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -579,6 +580,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1650,5 +1652,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/memories2.txt b/crates/fayalite/tests/sim/expected/memories2.txt index 1f78fcf..239802c 100644 --- a/crates/fayalite/tests/sim/expected/memories2.txt +++ b/crates/fayalite/tests/sim/expected/memories2.txt @@ -526,6 +526,7 @@ Simulation { }, pc: 52, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -607,6 +608,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1285,5 +1287,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/memories3.txt b/crates/fayalite/tests/sim/expected/memories3.txt index 75720a8..1fcbab1 100644 --- a/crates/fayalite/tests/sim/expected/memories3.txt +++ b/crates/fayalite/tests/sim/expected/memories3.txt @@ -1336,6 +1336,7 @@ Simulation { }, pc: 129, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1495,6 +1496,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -3345,5 +3347,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/mod1.txt b/crates/fayalite/tests/sim/expected/mod1.txt index a1de89a..ab144d3 100644 --- a/crates/fayalite/tests/sim/expected/mod1.txt +++ b/crates/fayalite/tests/sim/expected/mod1.txt @@ -187,6 +187,7 @@ Simulation { }, pc: 17, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -225,6 +226,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -577,5 +579,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/phantom_const.txt b/crates/fayalite/tests/sim/expected/phantom_const.txt index c9adae4..60ccff5 100644 --- a/crates/fayalite/tests/sim/expected/phantom_const.txt +++ b/crates/fayalite/tests/sim/expected/phantom_const.txt @@ -172,6 +172,7 @@ Simulation { }, pc: 16, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -215,6 +216,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -527,5 +529,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_1_false_false.txt b/crates/fayalite/tests/sim/expected/queue_1_false_false.txt index e349bbd..6586ce5 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_false_false.txt @@ -1083,6 +1083,7 @@ Simulation { }, pc: 134, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1201,6 +1202,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2160,5 +2162,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_1_false_true.txt b/crates/fayalite/tests/sim/expected/queue_1_false_true.txt index 3a31636..3fabc74 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_false_true.txt @@ -1064,6 +1064,7 @@ Simulation { }, pc: 132, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1180,6 +1181,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2139,5 +2141,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_1_true_false.txt b/crates/fayalite/tests/sim/expected/queue_1_true_false.txt index 9dd3851..54a2d06 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_true_false.txt @@ -1093,6 +1093,7 @@ Simulation { }, pc: 136, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1211,6 +1212,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2170,5 +2172,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_1_true_true.txt b/crates/fayalite/tests/sim/expected/queue_1_true_true.txt index 5762f24..f0e86e5 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_true_true.txt @@ -1074,6 +1074,7 @@ Simulation { }, pc: 134, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1190,6 +1191,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2149,5 +2151,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_2_false_false.txt b/crates/fayalite/tests/sim/expected/queue_2_false_false.txt index c2cb51a..6bf6992 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_false_false.txt @@ -1098,6 +1098,7 @@ Simulation { }, pc: 135, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1219,6 +1220,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2178,5 +2180,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_2_false_true.txt b/crates/fayalite/tests/sim/expected/queue_2_false_true.txt index f229451..2fe8866 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_false_true.txt @@ -1079,6 +1079,7 @@ Simulation { }, pc: 133, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1198,6 +1199,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2157,5 +2159,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_2_true_false.txt b/crates/fayalite/tests/sim/expected/queue_2_true_false.txt index e137316..cc340b8 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_true_false.txt @@ -1108,6 +1108,7 @@ Simulation { }, pc: 137, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1229,6 +1230,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2188,5 +2190,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_2_true_true.txt b/crates/fayalite/tests/sim/expected/queue_2_true_true.txt index 5203027..9cc2206 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_true_true.txt @@ -1089,6 +1089,7 @@ Simulation { }, pc: 135, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1208,6 +1209,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2167,5 +2169,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_3_false_false.txt b/crates/fayalite/tests/sim/expected/queue_3_false_false.txt index f5641ce..1086ca0 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_false_false.txt @@ -1125,6 +1125,7 @@ Simulation { }, pc: 139, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1248,6 +1249,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2187,5 +2189,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_3_false_true.txt b/crates/fayalite/tests/sim/expected/queue_3_false_true.txt index cde5489..1e95f7b 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_false_true.txt @@ -1106,6 +1106,7 @@ Simulation { }, pc: 137, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1227,6 +1228,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2166,5 +2168,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_3_true_false.txt b/crates/fayalite/tests/sim/expected/queue_3_true_false.txt index d943150..be9e7ef 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_true_false.txt @@ -1135,6 +1135,7 @@ Simulation { }, pc: 141, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1258,6 +1259,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2197,5 +2199,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_3_true_true.txt b/crates/fayalite/tests/sim/expected/queue_3_true_true.txt index 4a0f664..3e691c1 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_true_true.txt @@ -1116,6 +1116,7 @@ Simulation { }, pc: 139, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1237,6 +1238,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2176,5 +2178,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_4_false_false.txt b/crates/fayalite/tests/sim/expected/queue_4_false_false.txt index 4e0a067..c220ba9 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_false_false.txt @@ -1104,6 +1104,7 @@ Simulation { }, pc: 135, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1227,6 +1228,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2186,5 +2188,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_4_false_true.txt b/crates/fayalite/tests/sim/expected/queue_4_false_true.txt index a374f44..896783b 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_false_true.txt @@ -1085,6 +1085,7 @@ Simulation { }, pc: 133, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1206,6 +1207,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2165,5 +2167,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_4_true_false.txt b/crates/fayalite/tests/sim/expected/queue_4_true_false.txt index 7d20f26..4f500fa 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_true_false.txt @@ -1114,6 +1114,7 @@ Simulation { }, pc: 137, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1237,6 +1238,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2196,5 +2198,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/queue_4_true_true.txt b/crates/fayalite/tests/sim/expected/queue_4_true_true.txt index a0ee509..bf97cd2 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_true_true.txt @@ -1095,6 +1095,7 @@ Simulation { }, pc: 135, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -1216,6 +1217,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2175,5 +2177,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt index 6562d4d..9641ed5 100644 --- a/crates/fayalite/tests/sim/expected/ripple_counter.txt +++ b/crates/fayalite/tests/sim/expected/ripple_counter.txt @@ -636,6 +636,7 @@ Simulation { }, pc: 69, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -725,6 +726,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1790,5 +1792,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/shift_register.txt b/crates/fayalite/tests/sim/expected/shift_register.txt index 1eaa378..70ebccd 100644 --- a/crates/fayalite/tests/sim/expected/shift_register.txt +++ b/crates/fayalite/tests/sim/expected/shift_register.txt @@ -254,6 +254,7 @@ Simulation { }, pc: 34, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -293,6 +294,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -545,5 +547,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_fork_join.txt b/crates/fayalite/tests/sim/expected/sim_fork_join.txt index c66e77e..b291af7 100644 --- a/crates/fayalite/tests/sim/expected/sim_fork_join.txt +++ b/crates/fayalite/tests/sim/expected/sim_fork_join.txt @@ -60,6 +60,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -87,6 +88,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -521,5 +523,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt b/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt index ae88960..1b0efd5 100644 --- a/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt +++ b/crates/fayalite/tests/sim/expected/sim_fork_join_scope.txt @@ -60,6 +60,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -87,6 +88,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -521,5 +523,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_only_connects.txt b/crates/fayalite/tests/sim/expected/sim_only_connects.txt index 2ae2fbe..241ef46 100644 --- a/crates/fayalite/tests/sim/expected/sim_only_connects.txt +++ b/crates/fayalite/tests/sim/expected/sim_only_connects.txt @@ -375,6 +375,7 @@ Simulation { }, pc: 41, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -475,6 +476,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -1768,5 +1770,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_read_past.txt b/crates/fayalite/tests/sim/expected/sim_read_past.txt index f771434..3866eb9 100644 --- a/crates/fayalite/tests/sim/expected/sim_read_past.txt +++ b/crates/fayalite/tests/sim/expected/sim_read_past.txt @@ -512,6 +512,7 @@ Simulation { }, pc: 57, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -591,6 +592,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -9726,5 +9728,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt index 5584b73..b55fd8c 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async.txt @@ -48,6 +48,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -72,6 +73,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -539,5 +541,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt index f03c25a..29870da 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_async_immediate_reset.txt @@ -48,6 +48,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -72,6 +73,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -539,5 +541,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt index c93d6c1..0885cc9 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync.txt @@ -48,6 +48,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -72,6 +73,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -497,5 +499,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt index f13af84..068edb2 100644 --- a/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt +++ b/crates/fayalite/tests/sim/expected/sim_resettable_counter_sync_immediate_reset.txt @@ -48,6 +48,7 @@ Simulation { }, pc: 0, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [], }, @@ -72,6 +73,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -497,5 +499,6 @@ Simulation { }, ), }, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt b/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt index 0dd374c..4befbfc 100644 --- a/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt +++ b/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt @@ -494,6 +494,7 @@ Simulation { }, pc: 43, memory_write_log: [], + assert_failed_log: [], memories: StatePart { value: [ MemoryData { @@ -570,6 +571,7 @@ Simulation { .. }, }, + global_io: {}, main_module: SimulationModuleState { base_targets: [ Instance { @@ -2250,5 +2252,6 @@ Simulation { }), waiting_sensitivity_sets_by_address: {}, waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt new file mode 100644 index 0000000..bad046e --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt @@ -0,0 +1,522 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "", + ty: Enum { + HdlNone, + HdlSome, + }, + }, + SlotDebugData { + name: "", + ty: Enum { + HdlNone, + HdlSome, + }, + }, + ], + .. + }, + big_slots: StatePartLayout { + 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 { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(10), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x1, + }, + 1: Const { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x0, + }, + 2: Copy { + dest: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + src: StatePartIndex(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(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + start: 1, + len: 2, + }, + // at: module-XXXXXXXXXX.rs:3:1 + 4: AndBigWithSmallImmediate { + dest: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + lhs: StatePartIndex(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(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + src: StatePartIndex(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(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + start: 1, + len: 2, + }, + 7: CmpEq { + dest: StatePartIndex(11), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + }, + 8: CmpEq { + dest: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + rhs: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 9: Copy { + dest: StatePartIndex(8), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", ty: Bool }, + src: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:2:1 + 10: AndBigWithSmallImmediate { + dest: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + lhs: StatePartIndex(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(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x0, + }, + 12: BranchIfSmallNeImmediate { + target: 14, + lhs: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x0, + }, + 13: Copy { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(10), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + 14: BranchIfSmallNeImmediate { + target: 17, + lhs: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x1, + }, + 15: BranchIfSmallNeImmediate { + target: 17, + lhs: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x1, + }, + 16: Copy { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(11), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 17: Copy { + dest: StatePartIndex(6), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", ty: Bool }, + src: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 18: Copy { + dest: StatePartIndex(7), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", ty: Bool }, + src: StatePartIndex(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: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }, + global_io: {}, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.a, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.b, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.structural_eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.bit_eq, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.a, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.b, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.bit_eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.eq, + Instance { + name: ::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(0), + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x3, + last_state: 0x3, + }, + SimTrace { + id: TraceScalarId(2), + kind: EnumDiscriminant { + index: StatePartIndex(1), + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(5), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x3, + last_state: 0x3, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigBool { + index: StatePartIndex(6), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigBool { + index: StatePartIndex(7), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigBool { + index: StatePartIndex(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: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd new file mode 100644 index 0000000..8da11c9 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd @@ -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 diff --git a/crates/fayalite/tests/sim/expected/test_formal_counter.txt b/crates/fayalite/tests/sim/expected/test_formal_counter.txt new file mode 100644 index 0000000..fc90a1a --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_formal_counter.txt @@ -0,0 +1,855 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + 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 { + 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: "<>::formal_global_clock", + ty: Clock, + }, + SlotDebugData { + name: "<>::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: "<>::any_seq", + ty: UInt<16>, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:15:1 + 0: Copy { + dest: StatePartIndex(2), // (0x4d2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::any_seq_out", ty: UInt<16> }, + src: StatePartIndex(25), // (0x4d2) SlotDebugData { name: "<>::any_seq", ty: UInt<16> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 1: Copy { + dest: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(8), // (0x0) SlotDebugData { name: "<>::formal_reset", ty: SyncReset }, + }, + 2: NotU { + dest: StatePartIndex(20), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: Bool }, + width: 1, + }, + 3: Const { + dest: StatePartIndex(18), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x1, + }, + 4: And { + dest: StatePartIndex(21), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(18), // (0x1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(20), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + 5: NotU { + dest: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(21), // (0x1) SlotDebugData { name: "", ty: Bool }, + width: 1, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 6: Copy { + dest: StatePartIndex(24), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(18), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 7: Copy { + dest: StatePartIndex(0), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count", ty: UInt<8> }, + src: StatePartIndex(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(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> }, + value: 0xa, + }, + 9: CmpLe { + dest: StatePartIndex(17), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> }, + rhs: StatePartIndex(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> }, + }, + 10: Or { + dest: StatePartIndex(23), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(17), // (0x1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 11: BranchIfZero { + target: 13, + value: StatePartIndex(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(24), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(23), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + 13: IsNonZeroDestIsSmall { + dest: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(24), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 14: Const { + dest: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x1, + }, + 15: Add { + dest: StatePartIndex(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> }, + lhs: StatePartIndex(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> }, + rhs: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> }, + }, + 16: CmpLt { + dest: StatePartIndex(15), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> }, + rhs: StatePartIndex(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> }, + }, + 17: CastToUInt { + dest: StatePartIndex(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> }, + src: StatePartIndex(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> }, + dest_width: 8, + }, + // at: module-XXXXXXXXXX.rs:4:1 + 18: Copy { + dest: StatePartIndex(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> }, + src: StatePartIndex(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(15), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 20: Copy { + dest: StatePartIndex(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> }, + src: StatePartIndex(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 21: Const { + dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x0, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 22: BranchIfNonZero { + target: 24, + value: StatePartIndex(15), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 23: Copy { + dest: StatePartIndex(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> }, + src: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 24: Copy { + dest: StatePartIndex(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, + src: StatePartIndex(7), // (0x1) SlotDebugData { name: "<>::formal_global_clock", ty: Clock }, + }, + 25: Copy { + dest: StatePartIndex(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, + src: StatePartIndex(8), // (0x0) SlotDebugData { name: "<>::formal_reset", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:3:1 + 26: Copy { + dest: StatePartIndex(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock }, + src: StatePartIndex(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, + }, + 27: Copy { + dest: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset }, + src: StatePartIndex(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:4:1 + 28: IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock }, + }, + 29: AndSmall { + dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 30: IsNonZeroDestIsSmall { + dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset }, + }, + 31: BranchIfSmallZero { + target: 36, + value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 32: BranchIfSmallNonZero { + target: 35, + value: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 33: Copy { + dest: StatePartIndex(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> }, + src: StatePartIndex(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(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> }, + src: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 36: Assert { + clk_triggered: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + pred: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + assert_index: 0, + }, + // at: module-XXXXXXXXXX.rs:4:1 + 37: XorSmallImmediate { + dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(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: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }, + global_io: { + SimIoForGlobal( + formal_global_clock, + ): CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "<>::formal_global_clock", + ty: Clock, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 7, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + write: None, + }, + SimIoForGlobal( + formal_reset, + ): CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "<>::formal_reset", + ty: SyncReset, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 8, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + write: None, + }, + SimIoForGlobal( + any_seq( + UInt<16>, + ), + ): CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<16>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "<>::any_seq", + ty: UInt<16>, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 5, len: 0 }, + big_slots: StatePartIndexRange { start: 25, len: 1 }, + sim_only_slots: StatePartIndexRange { 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: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }.count, + Instance { + name: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }.enable_assert, + Instance { + name: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }.any_seq_out, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }.any_seq_out, + Instance { + name: ::formal_counter, + instantiated: Module { + name: formal_counter, + .. + }, + }.count, + Instance { + name: ::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(0), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0x02, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigBool { + index: StatePartIndex(1), + }, + maybe_changed: false, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<16>, + }, + maybe_changed: true, + state: 0x04d2, + last_state: 0x04d2, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigClock { + index: StatePartIndex(3), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigSyncReset { + index: StatePartIndex(4), + }, + maybe_changed: true, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigClock { + index: StatePartIndex(7), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigSyncReset { + index: StatePartIndex(8), + }, + maybe_changed: true, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigUInt { + index: StatePartIndex(9), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0x02, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(8), + kind: BigUInt { + index: StatePartIndex(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(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: "", + .. + }, + }, + ], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/test_formal_counter.vcd b/crates/fayalite/tests/sim/expected/test_formal_counter.vcd new file mode 100644 index 0000000..1ba1b18 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_formal_counter.vcd @@ -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 diff --git a/crates/fayalite/tests/sim/expected/test_formal_counter_assert.vcd b/crates/fayalite/tests/sim/expected/test_formal_counter_assert.vcd new file mode 100644 index 0000000..c9b1655 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_formal_counter_assert.vcd @@ -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 diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr index 8eff725..75bb262 100644 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr @@ -75,7 +75,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -214,7 +214,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -326,7 +326,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index f3af962..5c36374 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -151,6 +151,11 @@ "$kind": "Opaque" } }, + "NameIdOrGlobal": { + "data": { + "$kind": "ManualImpl" + } + }, "ScopedNameId": { "data": { "$kind": "Struct", @@ -1043,6 +1048,22 @@ "fold_where": "T: Fold", "visit_where": "T: Visit" }, + "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": { "data": { "$kind": "Opaque" @@ -1277,7 +1298,9 @@ "RegSync": "Visible", "RegAsync": "Visible", "Wire": "Visible", - "Instance": "Visible" + "Instance": "Visible", + "FormalInput": "Visible", + "SimIoForGlobal": "Visible" } }, "TargetChild": { @@ -1349,6 +1372,21 @@ "generics": "", "fold_where": "T: Fold", "visit_where": "T: Visit" + }, + "FormalInput": { + "data": { + "$kind": "Struct", + "$constructor": "FormalInput::new", + "kind()": "Visible", + "name_id()": "Visible", + "ty()": "Visible", + "source_location()": "Visible" + } + }, + "FormalInputKind": { + "data": { + "$kind": "Opaque" + } } } } \ No newline at end of file diff --git a/scripts/check-copyright.sh b/scripts/check-copyright.sh index 99205bb..779bcbf 100755 --- a/scripts/check-copyright.sh +++ b/scripts/check-copyright.sh @@ -47,7 +47,7 @@ function main() */LICENSE.md|*/Notices.txt) # copyright file ;; - /crates/fayalite/tests/ui/*.stderr|/crates/fayalite/tests/sim/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.txt) + /crates/fayalite/tests/ui/*.stderr|/crates/fayalite/tests/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.txt) # file that can't contain copyright header ;; /.forgejo/workflows/*.yml|*/.gitignore|*.toml|*/Makefile|*/_CoqProject)