Compare commits
	
		
			2 commits
		
	
	
		
			cdd84953d0
			...
			3458c21f44
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3458c21f44 | |||
| 43797db36e | 
					 9 changed files with 352 additions and 21 deletions
				
			
		|  | @ -83,6 +83,7 @@ impl ParsedBundle { | |||
|             custom_bounds, | ||||
|             no_static: _, | ||||
|             no_runtime_generics: _, | ||||
|             cmp_eq: _, | ||||
|         } = options.body; | ||||
|         let mut fields = match fields { | ||||
|             syn::Fields::Named(fields) => fields, | ||||
|  | @ -437,6 +438,7 @@ impl ToTokens for ParsedBundle { | |||
|             custom_bounds: _, | ||||
|             no_static, | ||||
|             no_runtime_generics, | ||||
|             cmp_eq, | ||||
|         } = &options.body; | ||||
|         let target = get_target(target, ident); | ||||
|         let mut item_attrs = attrs.clone(); | ||||
|  | @ -765,6 +767,69 @@ impl ToTokens for ParsedBundle { | |||
|             } | ||||
|         } | ||||
|         .to_tokens(tokens); | ||||
|         if let Some((cmp_eq,)) = cmp_eq { | ||||
|             let mut where_clause = | ||||
|                 Generics::from(generics) | ||||
|                     .where_clause | ||||
|                     .unwrap_or_else(|| syn::WhereClause { | ||||
|                         where_token: Token, | ||||
|                         predicates: Punctuated::new(), | ||||
|                     }); | ||||
|             let mut fields_cmp_eq = vec![]; | ||||
|             let mut fields_cmp_ne = vec![]; | ||||
|             for field in fields.named() { | ||||
|                 let field_ident = field.ident(); | ||||
|                 let field_ty = field.ty(); | ||||
|                 where_clause | ||||
|                     .predicates | ||||
|                     .push(parse_quote_spanned! {cmp_eq.span=> | ||||
|                         #field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty> | ||||
|                     }); | ||||
|                 fields_cmp_eq.push(quote_spanned! {span=> | ||||
|                     ::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident) | ||||
|                 }); | ||||
|                 fields_cmp_ne.push(quote_spanned! {span=> | ||||
|                     ::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident) | ||||
|                 }); | ||||
|             } | ||||
|             let cmp_eq_body; | ||||
|             let cmp_ne_body; | ||||
|             if fields_len == 0 { | ||||
|                 cmp_eq_body = quote_spanned! {span=> | ||||
|                     ::fayalite::expr::ToExpr::to_expr(&true) | ||||
|                 }; | ||||
|                 cmp_ne_body = quote_spanned! {span=> | ||||
|                     ::fayalite::expr::ToExpr::to_expr(&false) | ||||
|                 }; | ||||
|             } else { | ||||
|                 cmp_eq_body = quote_spanned! {span=> | ||||
|                     #(#fields_cmp_eq)&* | ||||
|                 }; | ||||
|                 cmp_ne_body = quote_spanned! {span=> | ||||
|                     #(#fields_cmp_ne)|* | ||||
|                 }; | ||||
|             }; | ||||
|             quote_spanned! {span=> | ||||
|                 #[automatically_derived] | ||||
|                 impl #impl_generics ::fayalite::expr::ops::ExprPartialEq<Self> for #target #type_generics | ||||
|                 #where_clause | ||||
|                 { | ||||
|                     fn cmp_eq( | ||||
|                         __lhs: ::fayalite::expr::Expr<Self>, | ||||
|                         __rhs: ::fayalite::expr::Expr<Self>, | ||||
|                     ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { | ||||
|                         #cmp_eq_body | ||||
|                     } | ||||
|                     fn cmp_ne( | ||||
|                         __lhs: ::fayalite::expr::Expr<Self>, | ||||
|                         __rhs: ::fayalite::expr::Expr<Self>, | ||||
|                     ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { | ||||
|                         #cmp_ne_body | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             .to_tokens(tokens); | ||||
|         } | ||||
|         if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { | ||||
|             let static_generics = generics.clone().for_static_type(); | ||||
|             let (static_impl_generics, static_type_generics, static_where_clause) = | ||||
|  |  | |||
|  | @ -155,7 +155,11 @@ impl ParsedEnum { | |||
|             custom_bounds, | ||||
|             no_static: _, | ||||
|             no_runtime_generics: _, | ||||
|             cmp_eq, | ||||
|         } = options.body; | ||||
|         if let Some((cmp_eq,)) = cmp_eq { | ||||
|             errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums"); | ||||
|         } | ||||
|         attrs.retain(|attr| { | ||||
|             if attr.path().is_ident("repr") { | ||||
|                 errors.error(attr, "#[repr] is not supported on #[hdl] enums"); | ||||
|  | @ -211,6 +215,7 @@ impl ToTokens for ParsedEnum { | |||
|             custom_bounds: _, | ||||
|             no_static, | ||||
|             no_runtime_generics, | ||||
|             cmp_eq: _, // TODO: implement cmp_eq for enums
 | ||||
|         } = &options.body; | ||||
|         let target = get_target(target, ident); | ||||
|         let mut struct_attrs = attrs.clone(); | ||||
|  |  | |||
|  | @ -49,10 +49,14 @@ impl ParsedTypeAlias { | |||
|             custom_bounds, | ||||
|             no_static, | ||||
|             no_runtime_generics: _, | ||||
|             cmp_eq, | ||||
|         } = options.body; | ||||
|         if let Some((no_static,)) = no_static { | ||||
|             errors.error(no_static, "no_static is not valid on type aliases"); | ||||
|         } | ||||
|         if let Some((cmp_eq,)) = cmp_eq { | ||||
|             errors.error(cmp_eq, "cmp_eq is not valid on type aliases"); | ||||
|         } | ||||
|         let generics = if custom_bounds.is_some() { | ||||
|             MaybeParsed::Unrecognized(generics) | ||||
|         } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) { | ||||
|  | @ -95,6 +99,7 @@ impl ToTokens for ParsedTypeAlias { | |||
|             custom_bounds: _, | ||||
|             no_static: _, | ||||
|             no_runtime_generics, | ||||
|             cmp_eq: _, | ||||
|         } = &options.body; | ||||
|         let target = get_target(target, ident); | ||||
|         let mut type_attrs = attrs.clone(); | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ crate::options! { | |||
|         CustomBounds(custom_bounds), | ||||
|         NoStatic(no_static), | ||||
|         NoRuntimeGenerics(no_runtime_generics), | ||||
|         CmpEq(cmp_eq), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -72,13 +72,14 @@ mod kw { | |||
|     custom_keyword!(cfg); | ||||
|     custom_keyword!(cfg_attr); | ||||
|     custom_keyword!(clock_domain); | ||||
|     custom_keyword!(cmp_eq); | ||||
|     custom_keyword!(connect_inexact); | ||||
|     custom_keyword!(custom_bounds); | ||||
|     custom_keyword!(flip); | ||||
|     custom_keyword!(hdl); | ||||
|     custom_keyword!(hdl_module); | ||||
|     custom_keyword!(input); | ||||
|     custom_keyword!(incomplete_wire); | ||||
|     custom_keyword!(input); | ||||
|     custom_keyword!(instance); | ||||
|     custom_keyword!(m); | ||||
|     custom_keyword!(memory); | ||||
|  |  | |||
|  | @ -2,8 +2,11 @@ | |||
| // See Notices.txt for copyright information
 | ||||
| 
 | ||||
| use crate::{ | ||||
|     expr::{ops::ArrayIndex, Expr, ToExpr}, | ||||
|     int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE}, | ||||
|     expr::{ | ||||
|         ops::{ArrayIndex, ArrayLiteral, ExprPartialEq}, | ||||
|         CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr, | ||||
|     }, | ||||
|     int::{Bool, DynSize, KnownSize, Size, SizeType, DYN_SIZE}, | ||||
|     intern::{Intern, Interned, LazyInterned}, | ||||
|     module::transform::visit::{Fold, Folder, Visit, Visitor}, | ||||
|     source_location::SourceLocation, | ||||
|  | @ -218,3 +221,36 @@ impl<T: Type, L: SizeType> Index<L> for ArrayWithoutLen<T> { | |||
|         Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<Lhs: Type, Rhs: Type, Len: Size> ExprPartialEq<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len> | ||||
| where | ||||
|     Lhs: ExprPartialEq<Rhs>, | ||||
| { | ||||
|     fn cmp_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> { | ||||
|         let lhs_ty = Expr::ty(lhs); | ||||
|         let rhs_ty = Expr::ty(rhs); | ||||
|         assert_eq!(lhs_ty.len(), rhs_ty.len()); | ||||
|         ArrayLiteral::<Bool, DynSize>::new( | ||||
|             Bool, | ||||
|             (0..lhs_ty.len()) | ||||
|                 .map(|i| Expr::canonical(lhs[i].cmp_eq(rhs[i]))) | ||||
|                 .collect(), | ||||
|         ) | ||||
|         .cast_to_bits() | ||||
|         .all_one_bits() | ||||
|     } | ||||
| 
 | ||||
|     fn cmp_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> { | ||||
|         let lhs_ty = Expr::ty(lhs); | ||||
|         let rhs_ty = Expr::ty(rhs); | ||||
|         assert_eq!(lhs_ty.len(), rhs_ty.len()); | ||||
|         ArrayLiteral::<Bool, DynSize>::new( | ||||
|             Bool, | ||||
|             (0..lhs_ty.len()) | ||||
|                 .map(|i| Expr::canonical(lhs[i].cmp_ne(rhs[i]))) | ||||
|                 .collect(), | ||||
|         ) | ||||
|         .cast_to_bits() | ||||
|         .any_one_bits() | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -2,7 +2,11 @@ | |||
| // See Notices.txt for copyright information
 | ||||
| 
 | ||||
| use crate::{ | ||||
|     expr::{ops::BundleLiteral, Expr, ToExpr}, | ||||
|     expr::{ | ||||
|         ops::{ArrayLiteral, BundleLiteral, ExprPartialEq}, | ||||
|         CastToBits, Expr, ReduceBits, ToExpr, | ||||
|     }, | ||||
|     int::{Bool, DynSize}, | ||||
|     intern::{Intern, Interned}, | ||||
|     sim::{SimValue, ToSimValue}, | ||||
|     source_location::SourceLocation, | ||||
|  | @ -325,7 +329,19 @@ macro_rules! impl_tuple_builder_fields { | |||
| } | ||||
| 
 | ||||
| macro_rules! impl_tuples { | ||||
|     ([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty:ident] $var:ident: $T:ident})*] []) => { | ||||
|     ( | ||||
|         [$({ | ||||
|             #[ | ||||
|                 num = $num:tt, | ||||
|                 field = $field:ident, | ||||
|                 ty = $ty_var:ident: $Ty:ident, | ||||
|                 lhs = $lhs_var:ident: $Lhs:ident, | ||||
|                 rhs = $rhs_var:ident: $Rhs:ident | ||||
|             ] | ||||
|             $var:ident: $T:ident | ||||
|         })*] | ||||
|         [] | ||||
|     ) => { | ||||
|         impl_tuple_builder_fields! { | ||||
|             {} | ||||
|             [$({ | ||||
|  | @ -498,6 +514,29 @@ macro_rules! impl_tuples { | |||
|                 Self::into_sim_value(*self, ty) | ||||
|             } | ||||
|         } | ||||
|         impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { | ||||
|             fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> { | ||||
|                 let ($($lhs_var,)*) = *lhs; | ||||
|                 let ($($rhs_var,)*) = *rhs; | ||||
|                 ArrayLiteral::<Bool, DynSize>::new( | ||||
|                     Bool, | ||||
|                     FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]), | ||||
|                 ) | ||||
|                 .cast_to_bits() | ||||
|                 .all_one_bits() | ||||
|             } | ||||
| 
 | ||||
|             fn cmp_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> { | ||||
|                 let ($($lhs_var,)*) = *lhs; | ||||
|                 let ($($rhs_var,)*) = *rhs; | ||||
|                 ArrayLiteral::<Bool, DynSize>::new( | ||||
|                     Bool, | ||||
|                     FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]), | ||||
|                 ) | ||||
|                 .cast_to_bits() | ||||
|                 .any_one_bits() | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { | ||||
|         impl_tuples!([$($lhs)*] []); | ||||
|  | @ -507,18 +546,18 @@ macro_rules! impl_tuples { | |||
| 
 | ||||
| impl_tuples! { | ||||
|     [] [ | ||||
|         {#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0} | ||||
|         {#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1} | ||||
|         {#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2} | ||||
|         {#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3} | ||||
|         {#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4} | ||||
|         {#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5} | ||||
|         {#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6} | ||||
|         {#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7} | ||||
|         {#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8} | ||||
|         {#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9} | ||||
|         {#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10} | ||||
|         {#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11} | ||||
|         {#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0} | ||||
|         {#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1} | ||||
|         {#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2} | ||||
|         {#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3} | ||||
|         {#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4} | ||||
|         {#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5} | ||||
|         {#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6} | ||||
|         {#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7} | ||||
|         {#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8} | ||||
|         {#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9} | ||||
|         {#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10} | ||||
|         {#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11} | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,10 @@ | |||
| // See Notices.txt for copyright information
 | ||||
| 
 | ||||
| use crate::{ | ||||
|     expr::{ops::VariantAccess, Expr, ToExpr}, | ||||
|     expr::{ | ||||
|         ops::{ExprPartialEq, VariantAccess}, | ||||
|         Expr, ToExpr, | ||||
|     }, | ||||
|     hdl, | ||||
|     int::Bool, | ||||
|     intern::{Intern, Interned}, | ||||
|  | @ -360,6 +363,60 @@ pub enum HdlOption<T: Type> { | |||
|     HdlSome(T), | ||||
| } | ||||
| 
 | ||||
| impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> for HdlOption<Lhs> { | ||||
|     #[hdl] | ||||
|     fn cmp_eq(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> { | ||||
|         #[hdl] | ||||
|         let cmp_eq = wire(); | ||||
|         #[hdl] | ||||
|         match lhs { | ||||
|             HdlSome(lhs) => | ||||
|             { | ||||
|                 #[hdl] | ||||
|                 match rhs { | ||||
|                     HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)), | ||||
|                     HdlNone => connect(cmp_eq, false), | ||||
|                 } | ||||
|             } | ||||
|             HdlNone => | ||||
|             { | ||||
|                 #[hdl] | ||||
|                 match rhs { | ||||
|                     HdlSome(_) => connect(cmp_eq, false), | ||||
|                     HdlNone => connect(cmp_eq, true), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         cmp_eq | ||||
|     } | ||||
| 
 | ||||
|     #[hdl] | ||||
|     fn cmp_ne(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> { | ||||
|         #[hdl] | ||||
|         let cmp_ne = wire(); | ||||
|         #[hdl] | ||||
|         match lhs { | ||||
|             HdlSome(lhs) => | ||||
|             { | ||||
|                 #[hdl] | ||||
|                 match rhs { | ||||
|                     HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)), | ||||
|                     HdlNone => connect(cmp_ne, true), | ||||
|                 } | ||||
|             } | ||||
|             HdlNone => | ||||
|             { | ||||
|                 #[hdl] | ||||
|                 match rhs { | ||||
|                     HdlSome(_) => connect(cmp_ne, true), | ||||
|                     HdlNone => connect(cmp_ne, false), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         cmp_ne | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[allow(non_snake_case)] | ||||
| pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> { | ||||
|     HdlOption[T::TYPE].HdlNone() | ||||
|  |  | |||
|  | @ -380,18 +380,18 @@ circuit check_written_inside_both_if_else: | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| #[hdl(outline_generated)] | ||||
| #[hdl(outline_generated, cmp_eq)] | ||||
| pub struct TestStruct<T> { | ||||
|     pub a: T, | ||||
|     pub b: UInt<8>, | ||||
| } | ||||
| 
 | ||||
| #[hdl(outline_generated)] | ||||
| #[hdl(outline_generated, cmp_eq)] | ||||
| pub struct TestStruct2 { | ||||
|     pub v: UInt<8>, | ||||
| } | ||||
| 
 | ||||
| #[hdl(outline_generated)] | ||||
| #[hdl(outline_generated, cmp_eq)] | ||||
| pub struct TestStruct3 {} | ||||
| 
 | ||||
| #[hdl_module(outline_generated)] | ||||
|  | @ -4425,3 +4425,125 @@ circuit check_let_patterns: | |||
| ",
 | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #[hdl_module(outline_generated)] | ||||
| pub fn check_struct_cmp_eq() { | ||||
|     #[hdl] | ||||
|     let tuple_lhs: (UInt<1>, SInt<1>, Bool) = m.input(); | ||||
|     #[hdl] | ||||
|     let tuple_rhs: (UInt<1>, SInt<1>, Bool) = m.input(); | ||||
|     #[hdl] | ||||
|     let tuple_cmp_eq: Bool = m.output(); | ||||
|     connect(tuple_cmp_eq, tuple_lhs.cmp_eq(tuple_rhs)); | ||||
|     #[hdl] | ||||
|     let tuple_cmp_ne: Bool = m.output(); | ||||
|     connect(tuple_cmp_ne, tuple_lhs.cmp_ne(tuple_rhs)); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let test_struct_lhs: TestStruct<SInt<8>> = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_rhs: TestStruct<SInt<8>> = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_cmp_eq: Bool = m.output(); | ||||
|     connect(test_struct_cmp_eq, test_struct_lhs.cmp_eq(test_struct_rhs)); | ||||
|     #[hdl] | ||||
|     let test_struct_cmp_ne: Bool = m.output(); | ||||
|     connect(test_struct_cmp_ne, test_struct_lhs.cmp_ne(test_struct_rhs)); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let test_struct_2_lhs: TestStruct2 = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_2_rhs: TestStruct2 = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_2_cmp_eq: Bool = m.output(); | ||||
|     connect( | ||||
|         test_struct_2_cmp_eq, | ||||
|         test_struct_2_lhs.cmp_eq(test_struct_2_rhs), | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let test_struct_2_cmp_ne: Bool = m.output(); | ||||
|     connect( | ||||
|         test_struct_2_cmp_ne, | ||||
|         test_struct_2_lhs.cmp_ne(test_struct_2_rhs), | ||||
|     ); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let test_struct_3_lhs: TestStruct3 = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_3_rhs: TestStruct3 = m.input(); | ||||
|     #[hdl] | ||||
|     let test_struct_3_cmp_eq: Bool = m.output(); | ||||
|     connect( | ||||
|         test_struct_3_cmp_eq, | ||||
|         test_struct_3_lhs.cmp_eq(test_struct_3_rhs), | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let test_struct_3_cmp_ne: Bool = m.output(); | ||||
|     connect( | ||||
|         test_struct_3_cmp_ne, | ||||
|         test_struct_3_lhs.cmp_ne(test_struct_3_rhs), | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn test_struct_cmp_eq() { | ||||
|     let _n = SourceLocation::normalize_files_for_tests(); | ||||
|     let m = check_struct_cmp_eq(); | ||||
|     dbg!(m); | ||||
|     #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
 | ||||
|     assert_export_firrtl! { | ||||
|         m => | ||||
|         "/test/check_struct_cmp_eq.fir": r"FIRRTL version 3.2.0
 | ||||
| circuit check_struct_cmp_eq: | ||||
|     type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>} | ||||
|     type Ty1 = {a: SInt<8>, b: UInt<8>} | ||||
|     type Ty2 = {v: UInt<8>} | ||||
|     type Ty3 = {} | ||||
|     module check_struct_cmp_eq: @[module-XXXXXXXXXX.rs 1:1] | ||||
|         input tuple_lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] | ||||
|         input tuple_rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] | ||||
|         output tuple_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] | ||||
|         output tuple_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 6:1] | ||||
|         input test_struct_lhs: Ty1 @[module-XXXXXXXXXX.rs 8:1] | ||||
|         input test_struct_rhs: Ty1 @[module-XXXXXXXXXX.rs 9:1] | ||||
|         output test_struct_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 10:1] | ||||
|         output test_struct_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 12:1] | ||||
|         input test_struct_2_lhs: Ty2 @[module-XXXXXXXXXX.rs 14:1] | ||||
|         input test_struct_2_rhs: Ty2 @[module-XXXXXXXXXX.rs 15:1] | ||||
|         output test_struct_2_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 16:1] | ||||
|         output test_struct_2_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 18:1] | ||||
|         input test_struct_3_lhs: Ty3 @[module-XXXXXXXXXX.rs 20:1] | ||||
|         input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1] | ||||
|         output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1] | ||||
|         output test_struct_3_cmp_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] | ||||
|         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_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] | ||||
| ",
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue