Compare commits
	
		
			1 commit
		
	
	
		
			c4b6a0fee6
			...
			43c29bf221
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 43c29bf221 | 
					 9 changed files with 817 additions and 370 deletions
				
			
		|  | @ -220,6 +220,7 @@ forward_fold!(syn::ExprArray => fold_expr_array); | ||||||
| forward_fold!(syn::ExprCall => fold_expr_call); | forward_fold!(syn::ExprCall => fold_expr_call); | ||||||
| forward_fold!(syn::ExprIf => fold_expr_if); | forward_fold!(syn::ExprIf => fold_expr_if); | ||||||
| forward_fold!(syn::ExprMatch => fold_expr_match); | forward_fold!(syn::ExprMatch => fold_expr_match); | ||||||
|  | forward_fold!(syn::ExprMethodCall => fold_expr_method_call); | ||||||
| forward_fold!(syn::ExprPath => fold_expr_path); | forward_fold!(syn::ExprPath => fold_expr_path); | ||||||
| forward_fold!(syn::ExprRepeat => fold_expr_repeat); | forward_fold!(syn::ExprRepeat => fold_expr_repeat); | ||||||
| forward_fold!(syn::ExprStruct => fold_expr_struct); | forward_fold!(syn::ExprStruct => fold_expr_struct); | ||||||
|  |  | ||||||
|  | @ -130,6 +130,8 @@ pub(crate) struct ParsedEnum { | ||||||
|     pub(crate) variants: Punctuated<ParsedVariant, Token![,]>, |     pub(crate) variants: Punctuated<ParsedVariant, Token![,]>, | ||||||
|     pub(crate) match_variant_ident: Ident, |     pub(crate) match_variant_ident: Ident, | ||||||
|     pub(crate) sim_value_ident: Ident, |     pub(crate) sim_value_ident: Ident, | ||||||
|  |     pub(crate) sim_builder_ident: Ident, | ||||||
|  |     pub(crate) sim_builder_ty_field_ident: Ident, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ParsedEnum { | impl ParsedEnum { | ||||||
|  | @ -192,6 +194,8 @@ impl ParsedEnum { | ||||||
|             variants, |             variants, | ||||||
|             match_variant_ident: format_ident!("__{}__MatchVariant", ident), |             match_variant_ident: format_ident!("__{}__MatchVariant", ident), | ||||||
|             sim_value_ident: format_ident!("__{}__SimValue", ident), |             sim_value_ident: format_ident!("__{}__SimValue", ident), | ||||||
|  |             sim_builder_ident: format_ident!("__{}__SimBuilder", ident), | ||||||
|  |             sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()), | ||||||
|             ident, |             ident, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  | @ -210,6 +214,8 @@ impl ToTokens for ParsedEnum { | ||||||
|             variants, |             variants, | ||||||
|             match_variant_ident, |             match_variant_ident, | ||||||
|             sim_value_ident, |             sim_value_ident, | ||||||
|  |             sim_builder_ident, | ||||||
|  |             sim_builder_ty_field_ident, | ||||||
|         } = self; |         } = self; | ||||||
|         let span = ident.span(); |         let span = ident.span(); | ||||||
|         let ItemOptions { |         let ItemOptions { | ||||||
|  | @ -412,6 +418,33 @@ impl ToTokens for ParsedEnum { | ||||||
|             )), |             )), | ||||||
|         } |         } | ||||||
|         .to_tokens(tokens); |         .to_tokens(tokens); | ||||||
|  |         let mut struct_attrs = attrs.clone(); | ||||||
|  |         struct_attrs.push(parse_quote_spanned! {span=> | ||||||
|  |             #[allow(dead_code, non_camel_case_types)] | ||||||
|  |         }); | ||||||
|  |         ItemStruct { | ||||||
|  |             attrs: struct_attrs, | ||||||
|  |             vis: vis.clone(), | ||||||
|  |             struct_token: Token, | ||||||
|  |             ident: sim_builder_ident.clone(), | ||||||
|  |             generics: generics.into(), | ||||||
|  |             fields: FieldsNamed { | ||||||
|  |                 brace_token: *brace_token, | ||||||
|  |                 named: Punctuated::from_iter([Field { | ||||||
|  |                     attrs: vec![], | ||||||
|  |                     vis: Visibility::Inherited, | ||||||
|  |                     mutability: FieldMutability::None, | ||||||
|  |                     ident: Some(sim_builder_ty_field_ident.clone()), | ||||||
|  |                     colon_token: Some(Token), | ||||||
|  |                     ty: parse_quote_spanned! {span=> | ||||||
|  |                         #target #type_generics | ||||||
|  |                     }, | ||||||
|  |                 }]), | ||||||
|  |             } | ||||||
|  |             .into(), | ||||||
|  |             semi_token: None, | ||||||
|  |         } | ||||||
|  |         .to_tokens(tokens); | ||||||
|         let mut enum_attrs = attrs.clone(); |         let mut enum_attrs = attrs.clone(); | ||||||
|         enum_attrs.push(parse_quote_spanned! {span=> |         enum_attrs.push(parse_quote_spanned! {span=> | ||||||
|             #[::fayalite::__std::prelude::v1::derive(
 |             #[::fayalite::__std::prelude::v1::derive(
 | ||||||
|  | @ -538,6 +571,25 @@ impl ToTokens for ParsedEnum { | ||||||
|                             ) |                             ) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |                     #[automatically_derived] | ||||||
|  |                     impl #impl_generics #sim_builder_ident #type_generics | ||||||
|  |                     #where_clause | ||||||
|  |                     { | ||||||
|  |                         #[allow(non_snake_case, dead_code)] | ||||||
|  |                         #vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>( | ||||||
|  |                             #self_token, | ||||||
|  |                             v: __V, | ||||||
|  |                         ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { | ||||||
|  |                             let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type( | ||||||
|  |                                 v, | ||||||
|  |                                 #self_token.#sim_builder_ty_field_ident.#ident, | ||||||
|  |                             ); | ||||||
|  |                             ::fayalite::sim::value::SimValue::from_value( | ||||||
|  |                                 #self_token.#sim_builder_ty_field_ident, | ||||||
|  |                                 #sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()), | ||||||
|  |                             ) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 quote_spanned! {span=> |                 quote_spanned! {span=> | ||||||
|  | @ -556,6 +608,18 @@ impl ToTokens for ParsedEnum { | ||||||
|                             ) |                             ) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |                     #[automatically_derived] | ||||||
|  |                     impl #impl_generics #sim_builder_ident #type_generics | ||||||
|  |                     #where_clause | ||||||
|  |                     { | ||||||
|  |                         #[allow(non_snake_case, dead_code)] | ||||||
|  |                         #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()), | ||||||
|  |                             ) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             .to_tokens(tokens); |             .to_tokens(tokens); | ||||||
|  | @ -848,6 +912,7 @@ impl ToTokens for ParsedEnum { | ||||||
|             impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics |             impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics | ||||||
|             #where_clause |             #where_clause | ||||||
|             { |             { | ||||||
|  |                 type SimBuilder = #sim_builder_ident #type_generics; | ||||||
|                 fn match_activate_scope( |                 fn match_activate_scope( | ||||||
|                     v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope, |                     v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope, | ||||||
|                 ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) { |                 ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) { | ||||||
|  | @ -884,6 +949,15 @@ impl ToTokens for ParsedEnum { | ||||||
|                     ::fayalite::sim::value::SimValue::from_value(ty, self) |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics> | ||||||
|  |             for #sim_builder_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self { | ||||||
|  |                     Self { #sim_builder_ty_field_ident } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         .to_tokens(tokens); |         .to_tokens(tokens); | ||||||
|         if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { |         if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { | ||||||
|  |  | ||||||
|  | @ -1687,6 +1687,8 @@ impl Fold for Visitor<'_> { | ||||||
|                 Repeat => process_hdl_repeat, |                 Repeat => process_hdl_repeat, | ||||||
|                 Struct => process_hdl_struct, |                 Struct => process_hdl_struct, | ||||||
|                 Tuple => process_hdl_tuple, |                 Tuple => process_hdl_tuple, | ||||||
|  |                 MethodCall => process_hdl_method_call, | ||||||
|  |                 Call => process_hdl_call, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,20 @@ | ||||||
|  | use std::mem; | ||||||
|  | 
 | ||||||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||||
| // See Notices.txt for copyright information
 | // See Notices.txt for copyright information
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     kw, |     kw, | ||||||
|     module::transform_body::{ExprOptions, Visitor}, |     module::transform_body::{ | ||||||
|  |         expand_match::{parse_enum_path, EnumPath}, | ||||||
|  |         ExprOptions, Visitor, | ||||||
|  |     }, | ||||||
|     HdlAttr, |     HdlAttr, | ||||||
| }; | }; | ||||||
| use quote::{format_ident, quote_spanned}; | use quote::{format_ident, quote_spanned}; | ||||||
| use syn::{ | use syn::{ | ||||||
|     parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, ExprRepeat, ExprStruct, |     parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::Paren, Expr, ExprArray, | ||||||
|     ExprTuple, FieldValue, TypePath, |     ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprStruct, ExprTuple, | ||||||
|  |     FieldValue, Token, TypePath, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| impl Visitor<'_> { | impl Visitor<'_> { | ||||||
|  | @ -162,4 +168,107 @@ impl Visitor<'_> { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     pub(crate) fn process_hdl_call( | ||||||
|  |         &mut self, | ||||||
|  |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|  |         mut expr_call: ExprCall, | ||||||
|  |     ) -> Expr { | ||||||
|  |         let span = hdl_attr.kw.span; | ||||||
|  |         let mut func = &mut *expr_call.func; | ||||||
|  |         let EnumPath { | ||||||
|  |             variant_path: _, | ||||||
|  |             enum_path, | ||||||
|  |             variant_name, | ||||||
|  |         } = loop { | ||||||
|  |             match func { | ||||||
|  |                 Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => { | ||||||
|  |                     func = &mut **expr; | ||||||
|  |                 } | ||||||
|  |                 Expr::Path(_) => { | ||||||
|  |                     let Expr::Path(ExprPath { attrs, qself, path }) = | ||||||
|  |                         mem::replace(func, Expr::PLACEHOLDER) | ||||||
|  |                     else { | ||||||
|  |                         unreachable!(); | ||||||
|  |                     }; | ||||||
|  |                     match parse_enum_path(TypePath { qself, path }) { | ||||||
|  |                         Ok(path) => break path, | ||||||
|  |                         Err(path) => { | ||||||
|  |                             self.errors.error(&path, "unsupported enum variant path"); | ||||||
|  |                             let TypePath { qself, path } = path; | ||||||
|  |                             *func = ExprPath { attrs, qself, path }.into(); | ||||||
|  |                             return expr_call.into(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 _ => { | ||||||
|  |                     self.errors.error( | ||||||
|  |                         &expr_call.func, | ||||||
|  |                         "#[hdl] function call -- function must be a possibly-parenthesized path", | ||||||
|  |                     ); | ||||||
|  |                     return expr_call.into(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         self.process_hdl_method_call( | ||||||
|  |             hdl_attr, | ||||||
|  |             ExprMethodCall { | ||||||
|  |                 attrs: expr_call.attrs, | ||||||
|  |                 receiver: parse_quote_spanned! {span=> | ||||||
|  |                     <#enum_path as ::fayalite::ty::StaticType>::TYPE | ||||||
|  |                 }, | ||||||
|  |                 dot_token: Token, | ||||||
|  |                 method: variant_name, | ||||||
|  |                 turbofish: None, | ||||||
|  |                 paren_token: expr_call.paren_token, | ||||||
|  |                 args: expr_call.args, | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |     pub(crate) fn process_hdl_method_call( | ||||||
|  |         &mut self, | ||||||
|  |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|  |         mut expr_method_call: ExprMethodCall, | ||||||
|  |     ) -> Expr { | ||||||
|  |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|  |         let span = hdl_attr.kw.span; | ||||||
|  |         // remove any number of groups and up to one paren
 | ||||||
|  |         let mut receiver = &mut *expr_method_call.receiver; | ||||||
|  |         let mut has_group = false; | ||||||
|  |         let receiver = loop { | ||||||
|  |             match receiver { | ||||||
|  |                 Expr::Group(ExprGroup { expr, .. }) => { | ||||||
|  |                     has_group = true; | ||||||
|  |                     receiver = expr; | ||||||
|  |                 } | ||||||
|  |                 Expr::Paren(ExprParen { expr, .. }) => break &mut **expr, | ||||||
|  |                 receiver @ Expr::Path(_) => break receiver, | ||||||
|  |                 _ => { | ||||||
|  |                     if !has_group { | ||||||
|  |                         self.errors.error( | ||||||
|  |                             &expr_method_call.receiver, | ||||||
|  |                             "#[hdl] on a method call needs parenthesized receiver", | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                     break &mut *expr_method_call.receiver; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         let func = if sim.is_some() { | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::enum_::enum_type_to_sim_builder | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::enum_::assert_is_enum_type | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         *expr_method_call.receiver = ExprCall { | ||||||
|  |             attrs: vec![], | ||||||
|  |             func, | ||||||
|  |             paren_token: Paren(span), | ||||||
|  |             args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]), | ||||||
|  |         } | ||||||
|  |         .into(); | ||||||
|  |         expr_method_call.into() | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -380,13 +380,13 @@ impl ToTokens for MatchPatSimple { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct EnumPath { | pub(crate) struct EnumPath { | ||||||
|     variant_path: Path, |     pub(crate) variant_path: Path, | ||||||
|     enum_path: Path, |     pub(crate) enum_path: Path, | ||||||
|     variant_name: Ident, |     pub(crate) variant_name: Ident, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> { | pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> { | ||||||
|     let TypePath { |     let TypePath { | ||||||
|         qself: None, |         qself: None, | ||||||
|         path: variant_path, |         path: variant_path, | ||||||
|  |  | ||||||
|  | @ -259,6 +259,7 @@ pub trait EnumType: | ||||||
|     MatchVariantsIter = EnumMatchVariantsIter<Self>, |     MatchVariantsIter = EnumMatchVariantsIter<Self>, | ||||||
| > | > | ||||||
| { | { | ||||||
|  |     type SimBuilder: From<Self>; | ||||||
|     fn variants(&self) -> Interned<[EnumVariant]>; |     fn variants(&self) -> Interned<[EnumVariant]>; | ||||||
|     fn match_activate_scope( |     fn match_activate_scope( | ||||||
|         v: Self::MatchVariantAndInactiveScope, |         v: Self::MatchVariantAndInactiveScope, | ||||||
|  | @ -321,7 +322,18 @@ impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub struct NoBuilder { | ||||||
|  |     _ty: Enum, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Enum> for NoBuilder { | ||||||
|  |     fn from(_ty: Enum) -> Self { | ||||||
|  |         Self { _ty } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl EnumType for Enum { | impl EnumType for Enum { | ||||||
|  |     type SimBuilder = NoBuilder; | ||||||
|     fn match_activate_scope( |     fn match_activate_scope( | ||||||
|         v: Self::MatchVariantAndInactiveScope, |         v: Self::MatchVariantAndInactiveScope, | ||||||
|     ) -> (Self::MatchVariant, Self::MatchActiveScope) { |     ) -> (Self::MatchVariant, Self::MatchActiveScope) { | ||||||
|  | @ -389,6 +401,9 @@ pub struct EnumPaddingSimValue { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl EnumPaddingSimValue { | impl EnumPaddingSimValue { | ||||||
|  |     pub const fn new() -> Self { | ||||||
|  |         Self { bits: None } | ||||||
|  |     } | ||||||
|     pub fn bit_width(&self) -> Option<usize> { |     pub fn bit_width(&self) -> Option<usize> { | ||||||
|         self.bits.as_ref().map(UIntValue::width) |         self.bits.as_ref().map(UIntValue::width) | ||||||
|     } |     } | ||||||
|  | @ -659,6 +674,16 @@ impl<'a> EnumSimValueToBits<'a> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | pub fn assert_is_enum_type<T: EnumType>(v: T) -> T { | ||||||
|  |     v | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | pub fn enum_type_to_sim_builder<T: EnumType>(v: T) -> T::SimBuilder { | ||||||
|  |     v.into() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[hdl] | #[hdl] | ||||||
| pub enum HdlOption<T: Type> { | pub enum HdlOption<T: Type> { | ||||||
|     HdlNone, |     HdlNone, | ||||||
|  |  | ||||||
|  | @ -317,8 +317,13 @@ pub fn enums() { | ||||||
|     let which_out: UInt<2> = m.output(); |     let which_out: UInt<2> = m.output(); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let data_out: UInt<4> = m.output(); |     let data_out: UInt<4> = m.output(); | ||||||
|  |     let b_out_ty = HdlOption[(UInt[1], Bool)]; | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let b_out: HdlOption<(UInt<1>, Bool)> = m.output(); |     let b_out: HdlOption<(UInt, Bool)> = m.output(HdlOption[(UInt[1], Bool)]); | ||||||
|  |     #[hdl] | ||||||
|  |     let b2_out: HdlOption<(UInt<1>, Bool)> = m.output(); | ||||||
|  | 
 | ||||||
|  |     connect_any(b2_out, b_out); | ||||||
| 
 | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     struct MyStruct<T> { |     struct MyStruct<T> { | ||||||
|  | @ -358,7 +363,7 @@ pub fn enums() { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     connect(b_out, HdlNone()); |     connect(b_out, b_out_ty.HdlNone()); | ||||||
| 
 | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     match the_reg { |     match the_reg { | ||||||
|  | @ -369,7 +374,7 @@ pub fn enums() { | ||||||
|         MyEnum::B(v) => { |         MyEnum::B(v) => { | ||||||
|             connect(which_out, 1_hdl_u2); |             connect(which_out, 1_hdl_u2); | ||||||
|             connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1)); |             connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1)); | ||||||
|             connect(b_out, HdlSome(v)); |             connect_any(b_out, HdlSome(v)); | ||||||
|         } |         } | ||||||
|         MyEnum::C(v) => { |         MyEnum::C(v) => { | ||||||
|             connect(which_out, 2_hdl_u2); |             connect(which_out, 2_hdl_u2); | ||||||
|  | @ -396,100 +401,125 @@ fn test_enums() { | ||||||
|     sim.write(sim.io().cd.rst, false); |     sim.write(sim.io().cd.rst, false); | ||||||
|     sim.advance_time(SimDuration::from_nanos(900)); |     sim.advance_time(SimDuration::from_nanos(900)); | ||||||
|     #[hdl(cmp_eq)] |     #[hdl(cmp_eq)] | ||||||
|     struct IO { |     struct IO<W: Size> { | ||||||
|         en: Bool, |         en: Bool, | ||||||
|         which_in: UInt<2>, |         which_in: UInt<2>, | ||||||
|         data_in: UInt<4>, |         data_in: UInt<4>, | ||||||
|         which_out: UInt<2>, |         which_out: UInt<2>, | ||||||
|         data_out: UInt<4>, |         data_out: UInt<4>, | ||||||
|         b_out: HdlOption<(UInt<1>, Bool)>, |         b_out: HdlOption<(UIntType<W>, Bool)>, | ||||||
|  |         b2_out: HdlOption<(UInt<1>, Bool)>, | ||||||
|     } |     } | ||||||
|  |     let io_ty = IO[1]; | ||||||
|     let io_cycles = [ |     let io_cycles = [ | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: false, |             en: false, | ||||||
|             which_in: 0_hdl_u2, |             which_in: 0_hdl_u2, | ||||||
|             data_in: 0_hdl_u4, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 0_hdl_u2, |             which_out: 0_hdl_u2, | ||||||
|             data_out: 0_hdl_u4, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlNone(), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlNone(), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlNone(), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1_hdl_u2, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0_hdl_u4, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 0_hdl_u2, |             which_out: 0_hdl_u2, | ||||||
|             data_out: 0_hdl_u4, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlNone(), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlNone(), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlNone(), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: false, |             en: false, | ||||||
|             which_in: 0_hdl_u2, |             which_in: 0_hdl_u2, | ||||||
|             data_in: 0_hdl_u4, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 1_hdl_u2, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0_hdl_u4, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlSome((0_hdl_u1, false)), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlSome((0u8.cast_to(UInt[1]), false)), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1_hdl_u2, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0xF_hdl_u4, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1_hdl_u2, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0_hdl_u4, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlSome((0_hdl_u1, false)), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlSome((0u8.cast_to(UInt[1]), false)), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1_hdl_u2, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0xF_hdl_u4, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1_hdl_u2, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0x3_hdl_u4, |             data_out: 0x3_hdl_u4, | ||||||
|             b_out: HdlSome((1_hdl_u1, true)), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlSome((1u8.cast_to(UInt[1]), true)), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 2_hdl_u2, |             which_in: 2_hdl_u2, | ||||||
|             data_in: 0xF_hdl_u4, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1_hdl_u2, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0x3_hdl_u4, |             data_out: 0x3_hdl_u4, | ||||||
|             b_out: HdlSome((1_hdl_u1, true)), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlSome((1u8.cast_to(UInt[1]), true)), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 2_hdl_u2, |             which_in: 2_hdl_u2, | ||||||
|             data_in: 0xF_hdl_u4, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 2_hdl_u2, |             which_out: 2_hdl_u2, | ||||||
|             data_out: 0xF_hdl_u4, |             data_out: 0xF_hdl_u4, | ||||||
|             b_out: HdlNone(), |             b_out: #[hdl(sim)] | ||||||
|  |             (io_ty.b_out).HdlNone(), | ||||||
|  |             b2_out: #[hdl(sim)] | ||||||
|  |             HdlNone(), | ||||||
|         }, |         }, | ||||||
|     ]; |     ]; | ||||||
|     for (cycle, expected) in io_cycles.into_iter().enumerate() { |     for (cycle, expected) in io_cycles.into_iter().enumerate() { | ||||||
|         #[hdl(sim)] |         #[hdl(sim)] | ||||||
|         let IO { |         let IO::<_> { | ||||||
|             en, |             en, | ||||||
|             which_in, |             which_in, | ||||||
|             data_in, |             data_in, | ||||||
|             which_out: _, |             which_out: _, | ||||||
|             data_out: _, |             data_out: _, | ||||||
|             b_out: _, |             b_out: _, | ||||||
|  |             b2_out: _, | ||||||
|         } = expected; |         } = expected; | ||||||
|         sim.write(sim.io().en, &en); |         sim.write(sim.io().en, &en); | ||||||
|         sim.write(sim.io().which_in, &which_in); |         sim.write(sim.io().which_in, &which_in); | ||||||
|         sim.write(sim.io().data_in, &data_in); |         sim.write(sim.io().data_in, &data_in); | ||||||
|         let io = #[hdl(sim)] |         let io = #[hdl(sim)] | ||||||
|         IO { |         IO::<_> { | ||||||
|             en, |             en, | ||||||
|             which_in, |             which_in, | ||||||
|             data_in, |             data_in, | ||||||
|             which_out: sim.read(sim.io().which_out), |             which_out: sim.read(sim.io().which_out), | ||||||
|             data_out: sim.read(sim.io().data_out), |             data_out: sim.read(sim.io().data_out), | ||||||
|             b_out: sim.read(sim.io().b_out), |             b_out: sim.read(sim.io().b_out), | ||||||
|  |             b2_out: sim.read(sim.io().b2_out), | ||||||
|         }; |         }; | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             expected, |             expected, | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -16,18 +16,25 @@ $var wire 1 ) \0 $end | ||||||
| $var wire 1 * \1 $end | $var wire 1 * \1 $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $scope struct the_reg $end | $scope struct b2_out $end | ||||||
| $var string 1 + \$tag $end | $var string 1 + \$tag $end | ||||||
|  | $scope struct HdlSome $end | ||||||
|  | $var wire 1 , \0 $end | ||||||
|  | $var wire 1 - \1 $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct the_reg $end | ||||||
|  | $var string 1 . \$tag $end | ||||||
| $scope struct B $end | $scope struct B $end | ||||||
| $var reg 1 , \0 $end | $var reg 1 / \0 $end | ||||||
| $var reg 1 - \1 $end | $var reg 1 0 \1 $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $scope struct C $end | $scope struct C $end | ||||||
| $scope struct a $end | $scope struct a $end | ||||||
| $var reg 1 . \[0] $end | $var reg 1 1 \[0] $end | ||||||
| $var reg 1 / \[1] $end | $var reg 1 2 \[1] $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $var reg 2 0 b $end | $var reg 2 3 b $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $upscope $end | $upscope $end | ||||||
|  | @ -43,12 +50,15 @@ b0 ' | ||||||
| sHdlNone\x20(0) ( | sHdlNone\x20(0) ( | ||||||
| 0) | 0) | ||||||
| 0* | 0* | ||||||
| sA\x20(0) + | sHdlNone\x20(0) + | ||||||
| 0, | 0, | ||||||
| 0- | 0- | ||||||
| 0. | sA\x20(0) . | ||||||
| 0/ | 0/ | ||||||
| b0 0 | 00 | ||||||
|  | 01 | ||||||
|  | 02 | ||||||
|  | b0 3 | ||||||
| $end | $end | ||||||
| #1000000 | #1000000 | ||||||
| 1! | 1! | ||||||
|  | @ -66,7 +76,8 @@ b1 $ | ||||||
| 1! | 1! | ||||||
| b1 & | b1 & | ||||||
| sHdlSome\x20(1) ( | sHdlSome\x20(1) ( | ||||||
| sB\x20(1) + | sHdlSome\x20(1) + | ||||||
|  | sB\x20(1) . | ||||||
| #6000000 | #6000000 | ||||||
| 0# | 0# | ||||||
| b0 $ | b0 $ | ||||||
|  | @ -85,8 +96,10 @@ b11 ' | ||||||
| 1* | 1* | ||||||
| 1, | 1, | ||||||
| 1- | 1- | ||||||
| 1. |  | ||||||
| 1/ | 1/ | ||||||
|  | 10 | ||||||
|  | 11 | ||||||
|  | 12 | ||||||
| #10000000 | #10000000 | ||||||
| 0! | 0! | ||||||
| #11000000 | #11000000 | ||||||
|  | @ -101,8 +114,11 @@ b1111 ' | ||||||
| sHdlNone\x20(0) ( | sHdlNone\x20(0) ( | ||||||
| 0) | 0) | ||||||
| 0* | 0* | ||||||
| sC\x20(2) + | sHdlNone\x20(0) + | ||||||
| b11 0 | 0, | ||||||
|  | 0- | ||||||
|  | sC\x20(2) . | ||||||
|  | b11 3 | ||||||
| #14000000 | #14000000 | ||||||
| 0! | 0! | ||||||
| #15000000 | #15000000 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue