forked from libre-chip/fayalite
		
	add #[hdl(cmp_eq)] to implement HdlPartialEq automatically
This commit is contained in:
		
							parent
							
								
									43797db36e
								
							
						
					
					
						commit
						3458c21f44
					
				
					 9 changed files with 351 additions and 20 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,6 +72,7 @@ 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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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