forked from libre-chip/fayalite
		
	expand SimValue support
This commit is contained in:
		
							parent
							
								
									5028401a5a
								
							
						
					
					
						commit
						a40eaaa2da
					
				
					 13 changed files with 864 additions and 342 deletions
				
			
		|  | @ -692,6 +692,12 @@ impl ToTokens for ParsedBundle { | ||||||
|                 v.field_to_bits(&value.#ident); |                 v.field_to_bits(&value.#ident); | ||||||
|             } |             } | ||||||
|         })); |         })); | ||||||
|  |         let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { | ||||||
|  |             let ident: &Ident = field.ident().as_ref().unwrap(); | ||||||
|  |             quote_spanned! {span=> | ||||||
|  |                 #ident: ::fayalite::sim::value::SimValue::ty(&self.#ident), | ||||||
|  |             } | ||||||
|  |         })); | ||||||
|         let fields_len = fields.named().into_iter().len(); |         let fields_len = fields.named().into_iter().len(); | ||||||
|         quote_spanned! {span=> |         quote_spanned! {span=> | ||||||
|             #[automatically_derived] |             #[automatically_derived] | ||||||
|  | @ -797,6 +803,51 @@ impl ToTokens for ParsedBundle { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             #[automatically_derived] |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 type Type = #mask_type_ident #type_generics; | ||||||
|  | 
 | ||||||
|  |                 fn to_sim_value( | ||||||
|  |                     &self, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                     <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                 > { | ||||||
|  |                     let ty = #mask_type_ident { | ||||||
|  |                         #(#to_sim_value_fields)* | ||||||
|  |                     }; | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) | ||||||
|  |                 } | ||||||
|  |                 fn into_sim_value( | ||||||
|  |                     self, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                     <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                 > { | ||||||
|  |                     let ty = #mask_type_ident { | ||||||
|  |                         #(#to_sim_value_fields)* | ||||||
|  |                     }; | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#mask_type_ident #type_generics> | ||||||
|  |             for #mask_type_sim_value_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 fn to_sim_value_with_type( | ||||||
|  |                     &self, | ||||||
|  |                     ty: #mask_type_ident #type_generics, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) | ||||||
|  |                 } | ||||||
|  |                 fn into_sim_value_with_type( | ||||||
|  |                     self, | ||||||
|  |                     ty: #mask_type_ident #type_generics, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             #[automatically_derived] | ||||||
|             impl #impl_generics ::fayalite::ty::Type for #target #type_generics |             impl #impl_generics ::fayalite::ty::Type for #target #type_generics | ||||||
|             #where_clause |             #where_clause | ||||||
|             { |             { | ||||||
|  | @ -900,6 +951,51 @@ impl ToTokens for ParsedBundle { | ||||||
|                     ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) |                     ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 type Type = #target #type_generics; | ||||||
|  | 
 | ||||||
|  |                 fn to_sim_value( | ||||||
|  |                     &self, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                     <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                 > { | ||||||
|  |                     let ty = #target { | ||||||
|  |                         #(#to_sim_value_fields)* | ||||||
|  |                     }; | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) | ||||||
|  |                 } | ||||||
|  |                 fn into_sim_value( | ||||||
|  |                     self, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                     <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                 > { | ||||||
|  |                     let ty = #target { | ||||||
|  |                         #(#to_sim_value_fields)* | ||||||
|  |                     }; | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> | ||||||
|  |             for #sim_value_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 fn to_sim_value_with_type( | ||||||
|  |                     &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)) | ||||||
|  |                 } | ||||||
|  |                 fn into_sim_value_with_type( | ||||||
|  |                     self, | ||||||
|  |                     ty: #target #type_generics, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         .to_tokens(tokens); |         .to_tokens(tokens); | ||||||
|         if let Some((cmp_eq,)) = cmp_eq { |         if let Some((cmp_eq,)) = cmp_eq { | ||||||
|  |  | ||||||
|  | @ -866,6 +866,24 @@ impl ToTokens for ParsedEnum { | ||||||
|                     ][..]) |                     ][..]) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             #[automatically_derived] | ||||||
|  |             impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> | ||||||
|  |             for #sim_value_ident #type_generics | ||||||
|  |             #where_clause | ||||||
|  |             { | ||||||
|  |                 fn to_sim_value_with_type( | ||||||
|  |                     &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)) | ||||||
|  |                 } | ||||||
|  |                 fn into_sim_value_with_type( | ||||||
|  |                     self, | ||||||
|  |                     ty: #target #type_generics, | ||||||
|  |                 ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { | ||||||
|  |                     ::fayalite::sim::value::SimValue::from_value(ty, self) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         .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) { | ||||||
|  | @ -921,6 +939,34 @@ impl ToTokens for ParsedEnum { | ||||||
|                     const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = |                     const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = | ||||||
|                         <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; |                         <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; | ||||||
|                 } |                 } | ||||||
|  |                 #[automatically_derived] | ||||||
|  |                 impl #static_impl_generics ::fayalite::sim::value::ToSimValue | ||||||
|  |                 for #sim_value_ident #static_type_generics | ||||||
|  |                 #static_where_clause | ||||||
|  |                 { | ||||||
|  |                     type Type = #target #static_type_generics; | ||||||
|  | 
 | ||||||
|  |                     fn to_sim_value( | ||||||
|  |                         &self, | ||||||
|  |                     ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                         <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                     > { | ||||||
|  |                         ::fayalite::sim::value::SimValue::from_value( | ||||||
|  |                             ::fayalite::ty::StaticType::TYPE, | ||||||
|  |                             ::fayalite::__std::clone::Clone::clone(self), | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                     fn into_sim_value( | ||||||
|  |                         self, | ||||||
|  |                     ) -> ::fayalite::sim::value::SimValue< | ||||||
|  |                         <Self as ::fayalite::sim::value::ToSimValue>::Type, | ||||||
|  |                     > { | ||||||
|  |                         ::fayalite::sim::value::SimValue::from_value( | ||||||
|  |                             ::fayalite::ty::StaticType::TYPE, | ||||||
|  |                             self, | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             .to_tokens(tokens); |             .to_tokens(tokens); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -93,6 +93,7 @@ mod kw { | ||||||
|     custom_keyword!(output); |     custom_keyword!(output); | ||||||
|     custom_keyword!(reg_builder); |     custom_keyword!(reg_builder); | ||||||
|     custom_keyword!(reset); |     custom_keyword!(reset); | ||||||
|  |     custom_keyword!(sim); | ||||||
|     custom_keyword!(skip); |     custom_keyword!(skip); | ||||||
|     custom_keyword!(target); |     custom_keyword!(target); | ||||||
|     custom_keyword!(wire); |     custom_keyword!(wire); | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ use std::{borrow::Borrow, convert::Infallible}; | ||||||
| use syn::{ | use syn::{ | ||||||
|     fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold}, |     fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold}, | ||||||
|     parenthesized, |     parenthesized, | ||||||
|     parse::{Nothing, Parse, ParseStream}, |     parse::{Parse, ParseStream}, | ||||||
|     parse_quote, parse_quote_spanned, |     parse_quote, parse_quote_spanned, | ||||||
|     spanned::Spanned, |     spanned::Spanned, | ||||||
|     token::Paren, |     token::Paren, | ||||||
|  | @ -27,6 +27,13 @@ use syn::{ | ||||||
| mod expand_aggregate_literals; | mod expand_aggregate_literals; | ||||||
| mod expand_match; | mod expand_match; | ||||||
| 
 | 
 | ||||||
|  | options! { | ||||||
|  |     #[options = ExprOptions] | ||||||
|  |     pub(crate) enum ExprOption { | ||||||
|  |         Sim(sim), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| options! { | options! { | ||||||
|     pub(crate) enum LetFnKind { |     pub(crate) enum LetFnKind { | ||||||
|         Input(input), |         Input(input), | ||||||
|  | @ -952,7 +959,7 @@ with_debug_clone_and_fold! { | ||||||
|     #[allow(dead_code)] |     #[allow(dead_code)] | ||||||
|     pub(crate) struct HdlLet<Kind = HdlLetKind> { |     pub(crate) struct HdlLet<Kind = HdlLetKind> { | ||||||
|         pub(crate) attrs: Vec<Attribute>, |         pub(crate) attrs: Vec<Attribute>, | ||||||
|         pub(crate) hdl_attr: HdlAttr<Nothing, kw::hdl>, |         pub(crate) hdl_attr: HdlAttr<syn::parse::Nothing, kw::hdl>, | ||||||
|         pub(crate) let_token: Token![let], |         pub(crate) let_token: Token![let], | ||||||
|         pub(crate) mut_token: Option<Token![mut]>, |         pub(crate) mut_token: Option<Token![mut]>, | ||||||
|         pub(crate) name: Ident, |         pub(crate) name: Ident, | ||||||
|  | @ -1173,7 +1180,7 @@ impl Visitor<'_> { | ||||||
|             Some(_) => {} |             Some(_) => {} | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing, kw::hdl>, expr_if: ExprIf) -> Expr { |     fn process_hdl_if(&mut self, hdl_attr: HdlAttr<ExprOptions, kw::hdl>, expr_if: ExprIf) -> Expr { | ||||||
|         let ExprIf { |         let ExprIf { | ||||||
|             attrs, |             attrs, | ||||||
|             if_token, |             if_token, | ||||||
|  | @ -1181,10 +1188,10 @@ impl Visitor<'_> { | ||||||
|             then_branch, |             then_branch, | ||||||
|             else_branch, |             else_branch, | ||||||
|         } = expr_if; |         } = expr_if; | ||||||
|         self.require_normal_module_or_fn(if_token); |         let (else_token, else_expr) = else_branch.unzip(); | ||||||
|         let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr { |         let else_expr = else_expr.map(|else_expr| match *else_expr { | ||||||
|             Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if), |             Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)), | ||||||
|             expr => expr, |             _ => else_expr, | ||||||
|         }); |         }); | ||||||
|         if let Expr::Let(ExprLet { |         if let Expr::Let(ExprLet { | ||||||
|             attrs: let_attrs, |             attrs: let_attrs, | ||||||
|  | @ -1206,7 +1213,19 @@ impl Visitor<'_> { | ||||||
|                 }, |                 }, | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|         if let Some(else_expr) = else_expr { |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|  |         if sim.is_some() { | ||||||
|  |             ExprIf { | ||||||
|  |                 attrs, | ||||||
|  |                 if_token, | ||||||
|  |                 cond: parse_quote_spanned! {if_token.span=> | ||||||
|  |                     *::fayalite::sim::value::SimValue::<::fayalite::int::Bool>::value(&::fayalite::sim::value::ToSimValue::into_sim_value(#cond)) | ||||||
|  |                 }, | ||||||
|  |                 then_branch, | ||||||
|  |                 else_branch: else_token.zip(else_expr), | ||||||
|  |             } | ||||||
|  |             .into() | ||||||
|  |         } else if let Some(else_expr) = else_expr { | ||||||
|             parse_quote_spanned! {if_token.span=> |             parse_quote_spanned! {if_token.span=> | ||||||
|                 #(#attrs)* |                 #(#attrs)* | ||||||
|                 { |                 { | ||||||
|  | @ -1675,7 +1694,7 @@ impl Fold for Visitor<'_> { | ||||||
|     fn fold_local(&mut self, mut let_stmt: Local) -> Local { |     fn fold_local(&mut self, mut let_stmt: Local) -> Local { | ||||||
|         match self |         match self | ||||||
|             .errors |             .errors | ||||||
|             .ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr( |             .ok(HdlAttr::<ExprOptions, kw::hdl>::parse_and_leave_attr( | ||||||
|                 &let_stmt.attrs, |                 &let_stmt.attrs, | ||||||
|             )) { |             )) { | ||||||
|             None => return empty_let(), |             None => return empty_let(), | ||||||
|  | @ -1694,10 +1713,11 @@ impl Fold for Visitor<'_> { | ||||||
|             subpat: None, |             subpat: None, | ||||||
|         }) = pat |         }) = pat | ||||||
|         else { |         else { | ||||||
|             let hdl_attr = HdlAttr::<Nothing, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs) |             let hdl_attr = | ||||||
|                 .ok() |                 HdlAttr::<ExprOptions, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs) | ||||||
|                 .flatten() |                     .ok() | ||||||
|                 .expect("already checked above"); |                     .flatten() | ||||||
|  |                     .expect("already checked above"); | ||||||
|             let let_stmt = fold_local(self, let_stmt); |             let let_stmt = fold_local(self, let_stmt); | ||||||
|             return self.process_hdl_let_pat(hdl_attr, let_stmt); |             return self.process_hdl_let_pat(hdl_attr, let_stmt); | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|  | @ -1,45 +1,97 @@ | ||||||
| // 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::{kw, module::transform_body::Visitor, HdlAttr}; | use crate::{ | ||||||
|  |     kw, | ||||||
|  |     module::transform_body::{ExprOptions, Visitor}, | ||||||
|  |     HdlAttr, | ||||||
|  | }; | ||||||
| use quote::{format_ident, quote_spanned}; | use quote::{format_ident, quote_spanned}; | ||||||
| use syn::{ | use syn::{ | ||||||
|     parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, |     parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, ExprRepeat, ExprStruct, | ||||||
|     ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath, |     ExprTuple, FieldValue, TypePath, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| impl Visitor<'_> { | impl Visitor<'_> { | ||||||
|     pub(crate) fn process_hdl_array( |     pub(crate) fn process_hdl_array( | ||||||
|         &mut self, |         &mut self, | ||||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         mut expr_array: ExprArray, |         mut expr_array: ExprArray, | ||||||
|     ) -> Expr { |     ) -> Expr { | ||||||
|         self.require_normal_module_or_fn(hdl_attr); |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|         for elem in &mut expr_array.elems { |         let span = hdl_attr.kw.span; | ||||||
|             *elem = parse_quote_spanned! {elem.span()=> |         if sim.is_some() { | ||||||
|                 ::fayalite::expr::ToExpr::to_expr(&(#elem)) |             for elem in &mut expr_array.elems { | ||||||
|             }; |                 *elem = parse_quote_spanned! {elem.span()=> | ||||||
|  |                     ::fayalite::sim::value::ToSimValue::to_sim_value(&(#elem)) | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_array) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             for elem in &mut expr_array.elems { | ||||||
|  |                 *elem = parse_quote_spanned! {elem.span()=> | ||||||
|  |                     ::fayalite::expr::ToExpr::to_expr(&(#elem)) | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::expr::ToExpr::to_expr(&#expr_array) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)} |  | ||||||
|     } |     } | ||||||
|     pub(crate) fn process_hdl_repeat( |     pub(crate) fn process_hdl_repeat( | ||||||
|         &mut self, |         &mut self, | ||||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         mut expr_repeat: ExprRepeat, |         mut expr_repeat: ExprRepeat, | ||||||
|     ) -> Expr { |     ) -> Expr { | ||||||
|         self.require_normal_module_or_fn(hdl_attr); |  | ||||||
|         let repeated_value = &expr_repeat.expr; |         let repeated_value = &expr_repeat.expr; | ||||||
|         *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|             ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) |         let span = hdl_attr.kw.span; | ||||||
|         }; |         if sim.is_some() { | ||||||
|         parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)} |             *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> | ||||||
|  |                 ::fayalite::sim::value::ToSimValue::to_sim_value(&(#repeated_value)) | ||||||
|  |             }; | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_repeat) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> | ||||||
|  |                 ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) | ||||||
|  |             }; | ||||||
|  |             parse_quote_spanned! {span=> | ||||||
|  |                 ::fayalite::expr::ToExpr::to_expr(&#expr_repeat) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     pub(crate) fn process_hdl_struct( |     pub(crate) fn process_hdl_struct( | ||||||
|         &mut self, |         &mut self, | ||||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         expr_struct: ExprStruct, |         mut expr_struct: ExprStruct, | ||||||
|     ) -> Expr { |     ) -> Expr { | ||||||
|         self.require_normal_module_or_fn(&hdl_attr); |  | ||||||
|         let name_span = expr_struct.path.segments.last().unwrap().ident.span(); |         let name_span = expr_struct.path.segments.last().unwrap().ident.span(); | ||||||
|  |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|  |         if sim.is_some() { | ||||||
|  |             let ty_path = TypePath { | ||||||
|  |                 qself: expr_struct.qself.take(), | ||||||
|  |                 path: expr_struct.path, | ||||||
|  |             }; | ||||||
|  |             expr_struct.path = parse_quote_spanned! {name_span=> | ||||||
|  |                 __SimValue::<#ty_path> | ||||||
|  |             }; | ||||||
|  |             for field in &mut expr_struct.fields { | ||||||
|  |                 let expr = &field.expr; | ||||||
|  |                 field.expr = parse_quote_spanned! {field.member.span()=> | ||||||
|  |                     ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)) | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             return parse_quote_spanned! {name_span=> | ||||||
|  |                 { | ||||||
|  |                     type __SimValue<T> = <T as ::fayalite::ty::Type>::SimValue; | ||||||
|  |                     let value: ::fayalite::sim::value::SimValue<#ty_path> = ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_struct); | ||||||
|  |                     value | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|         let builder_ident = format_ident!("__builder", span = name_span); |         let builder_ident = format_ident!("__builder", span = name_span); | ||||||
|         let empty_builder = if expr_struct.qself.is_some() |         let empty_builder = if expr_struct.qself.is_some() | ||||||
|             || expr_struct |             || expr_struct | ||||||
|  | @ -91,12 +143,23 @@ impl Visitor<'_> { | ||||||
|     } |     } | ||||||
|     pub(crate) fn process_hdl_tuple( |     pub(crate) fn process_hdl_tuple( | ||||||
|         &mut self, |         &mut self, | ||||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         expr_tuple: ExprTuple, |         mut expr_tuple: ExprTuple, | ||||||
|     ) -> Expr { |     ) -> Expr { | ||||||
|         self.require_normal_module_or_fn(hdl_attr); |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|         parse_quote_spanned! {expr_tuple.span()=> |         if sim.is_some() { | ||||||
|             ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) |             for element in &mut expr_tuple.elems { | ||||||
|  |                 *element = parse_quote_spanned! {element.span()=> | ||||||
|  |                     &(#element) | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             parse_quote_spanned! {expr_tuple.span()=> | ||||||
|  |                 ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_tuple) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             parse_quote_spanned! {expr_tuple.span()=> | ||||||
|  |                 ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,9 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|     fold::{impl_fold, DoFold}, |     fold::{impl_fold, DoFold}, | ||||||
|     kw, |     kw, | ||||||
|     module::transform_body::{empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, Visitor}, |     module::transform_body::{ | ||||||
|  |         empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, ExprOptions, Visitor, | ||||||
|  |     }, | ||||||
|     Errors, HdlAttr, PairsIterExt, |     Errors, HdlAttr, PairsIterExt, | ||||||
| }; | }; | ||||||
| use proc_macro2::{Span, TokenStream}; | use proc_macro2::{Span, TokenStream}; | ||||||
|  | @ -11,7 +13,6 @@ use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt}; | ||||||
| use std::collections::BTreeSet; | use std::collections::BTreeSet; | ||||||
| use syn::{ | use syn::{ | ||||||
|     fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold}, |     fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold}, | ||||||
|     parse::Nothing, |  | ||||||
|     parse_quote_spanned, |     parse_quote_spanned, | ||||||
|     punctuated::Punctuated, |     punctuated::Punctuated, | ||||||
|     spanned::Spanned, |     spanned::Spanned, | ||||||
|  | @ -981,7 +982,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> { | ||||||
| impl Visitor<'_> { | impl Visitor<'_> { | ||||||
|     pub(crate) fn process_hdl_let_pat( |     pub(crate) fn process_hdl_let_pat( | ||||||
|         &mut self, |         &mut self, | ||||||
|         _hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         mut let_stmt: Local, |         mut let_stmt: Local, | ||||||
|     ) -> Local { |     ) -> Local { | ||||||
|         let span = let_stmt.let_token.span(); |         let span = let_stmt.let_token.span(); | ||||||
|  | @ -996,7 +997,6 @@ impl Visitor<'_> { | ||||||
|             init, |             init, | ||||||
|             semi_token, |             semi_token, | ||||||
|         } = let_stmt; |         } = let_stmt; | ||||||
|         self.require_normal_module_or_fn(let_token); |  | ||||||
|         let Some(syn::LocalInit { |         let Some(syn::LocalInit { | ||||||
|             eq_token, |             eq_token, | ||||||
|             expr, |             expr, | ||||||
|  | @ -1031,29 +1031,48 @@ impl Visitor<'_> { | ||||||
|             errors: _, |             errors: _, | ||||||
|             bindings, |             bindings, | ||||||
|         } = state; |         } = state; | ||||||
|         let retval = parse_quote_spanned! {span=> |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|             let (#(#bindings,)* __scope,) = { |         let retval = if sim.is_some() { | ||||||
|                 type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; |             parse_quote_spanned! {span=> | ||||||
|                 let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); |                 let (#(#bindings,)*) = { | ||||||
|                 ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { |                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue; | ||||||
|                     #[allow(unused_variables)] |                     let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); | ||||||
|                     #check_let_stmt |                     #let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token | ||||||
|                     match __infallible {} |                     (#(#bindings,)*) | ||||||
|                 }); |  | ||||||
|                 let mut __match_iter = ::fayalite::module::match_(__match_expr); |  | ||||||
|                 let ::fayalite::__std::option::Option::Some(__match_variant) = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else { |  | ||||||
|                     ::fayalite::__std::unreachable!("#[hdl] let with uninhabited type"); |  | ||||||
|                 }; |                 }; | ||||||
|                 let ::fayalite::__std::option::Option::None = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else { |             } | ||||||
|                     ::fayalite::__std::unreachable!("#[hdl] let with refutable pattern"); |         } else { | ||||||
|                 }; |             parse_quote_spanned! {span=> | ||||||
|                 let (__match_variant, __scope) = |                 let (#(#bindings,)* __scope,) = { | ||||||
|                     ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( |                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; | ||||||
|                         __match_variant, |                     let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); | ||||||
|  |                     ::fayalite::expr::check_match_expr( | ||||||
|  |                         __match_expr, | ||||||
|  |                         |__match_value, __infallible| { | ||||||
|  |                             #[allow(unused_variables)] | ||||||
|  |                             #check_let_stmt | ||||||
|  |                             match __infallible {} | ||||||
|  |                         }, | ||||||
|                     ); |                     ); | ||||||
|                 #let_token #pat #eq_token __match_variant #semi_token |                     let mut __match_iter = ::fayalite::module::match_(__match_expr); | ||||||
|                 (#(#bindings,)* __scope,) |                     let ::fayalite::__std::option::Option::Some(__match_variant) = | ||||||
|             }; |                         ::fayalite::__std::iter::Iterator::next(&mut __match_iter) | ||||||
|  |                     else { | ||||||
|  |                         ::fayalite::__std::unreachable!("#[hdl] let with uninhabited type"); | ||||||
|  |                     }; | ||||||
|  |                     let ::fayalite::__std::option::Option::None = | ||||||
|  |                         ::fayalite::__std::iter::Iterator::next(&mut __match_iter) | ||||||
|  |                     else { | ||||||
|  |                         ::fayalite::__std::unreachable!("#[hdl] let with refutable pattern"); | ||||||
|  |                     }; | ||||||
|  |                     let (__match_variant, __scope) = | ||||||
|  |                         ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( | ||||||
|  |                             __match_variant, | ||||||
|  |                         ); | ||||||
|  |                     #let_token #pat #eq_token __match_variant #semi_token | ||||||
|  |                     (#(#bindings,)* __scope,) | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         match retval { |         match retval { | ||||||
|             syn::Stmt::Local(retval) => retval, |             syn::Stmt::Local(retval) => retval, | ||||||
|  | @ -1062,7 +1081,7 @@ impl Visitor<'_> { | ||||||
|     } |     } | ||||||
|     pub(crate) fn process_hdl_match( |     pub(crate) fn process_hdl_match( | ||||||
|         &mut self, |         &mut self, | ||||||
|         _hdl_attr: HdlAttr<Nothing, kw::hdl>, |         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||||
|         expr_match: ExprMatch, |         expr_match: ExprMatch, | ||||||
|     ) -> Expr { |     ) -> Expr { | ||||||
|         let span = expr_match.match_token.span(); |         let span = expr_match.match_token.span(); | ||||||
|  | @ -1074,7 +1093,6 @@ impl Visitor<'_> { | ||||||
|             brace_token: _, |             brace_token: _, | ||||||
|             arms, |             arms, | ||||||
|         } = expr_match; |         } = expr_match; | ||||||
|         self.require_normal_module_or_fn(match_token); |  | ||||||
|         let mut state = HdlMatchParseState { |         let mut state = HdlMatchParseState { | ||||||
|             match_span: span, |             match_span: span, | ||||||
|             errors: &mut self.errors, |             errors: &mut self.errors, | ||||||
|  | @ -1083,24 +1101,37 @@ impl Visitor<'_> { | ||||||
|             arms.into_iter() |             arms.into_iter() | ||||||
|                 .filter_map(|arm| MatchArm::parse(&mut state, arm).ok()), |                 .filter_map(|arm| MatchArm::parse(&mut state, arm).ok()), | ||||||
|         ); |         ); | ||||||
|         let expr = quote_spanned! {span=> |         let ExprOptions { sim } = hdl_attr.body; | ||||||
|             { |         let expr = if sim.is_some() { | ||||||
|                 type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; |             quote_spanned! {span=> | ||||||
|                 let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); |                 { | ||||||
|                 ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { |                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue; | ||||||
|                     #[allow(unused_variables)] |                     let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); | ||||||
|                     #check_match |                     #match_token *__match_expr { | ||||||
|                 }); |  | ||||||
|                 for __match_variant in ::fayalite::module::match_(__match_expr) { |  | ||||||
|                     let (__match_variant, __scope) = |  | ||||||
|                         ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( |  | ||||||
|                             __match_variant, |  | ||||||
|                         ); |  | ||||||
|                     #match_token __match_variant { |  | ||||||
|                         #(#arms)* |                         #(#arms)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } else { | ||||||
|  |             quote_spanned! {span=> | ||||||
|  |                 { | ||||||
|  |                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; | ||||||
|  |                     let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); | ||||||
|  |                     ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { | ||||||
|  |                         #[allow(unused_variables)] | ||||||
|  |                         #check_match | ||||||
|  |                     }); | ||||||
|  |                     for __match_variant in ::fayalite::module::match_(__match_expr) { | ||||||
|  |                         let (__match_variant, __scope) = | ||||||
|  |                             ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( | ||||||
|  |                                 __match_variant, | ||||||
|  |                             ); | ||||||
|  |                         #match_token __match_variant { | ||||||
|  |                             #(#arms)* | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         syn::parse2(expr).unwrap() |         syn::parse2(expr).unwrap() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ use crate::{ | ||||||
|     }, |     }, | ||||||
|     int::{Bool, DynSize}, |     int::{Bool, DynSize}, | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue}, |     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, |         impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, | ||||||
|  | @ -562,29 +562,29 @@ macro_rules! impl_tuples { | ||||||
|                 BundleLiteral::new(ty, field_values[..].intern()).to_expr() |                 BundleLiteral::new(ty, field_values[..].intern()).to_expr() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<CanonicalType> for ($($T,)*) { |         impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<CanonicalType> for ($($T,)*) { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |             fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|                 SimValue::into_canonical(ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty))) |                 SimValue::into_canonical(ToSimValueWithType::<Bundle>::to_sim_value_with_type(self, Bundle::from_canonical(ty))) | ||||||
|             } |             } | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> |             fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> | ||||||
|             { |             { | ||||||
|                 SimValue::into_canonical(ToSimValue::<Bundle>::into_sim_value(self, Bundle::from_canonical(ty))) |                 SimValue::into_canonical(ToSimValueWithType::<Bundle>::into_sim_value_with_type(self, Bundle::from_canonical(ty))) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<Bundle> for ($($T,)*) { |         impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<Bundle> for ($($T,)*) { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> { |             fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|                 let ($($var,)*) = self; |                 let ($($var,)*) = self; | ||||||
|                 let [$($ty_var,)*] = *ty.fields() else { |                 let [$($ty_var,)*] = *ty.fields() else { | ||||||
|                     panic!("bundle has wrong number of fields"); |                     panic!("bundle has wrong number of fields"); | ||||||
|                 }; |                 }; | ||||||
|                 $(let $var = $var.to_sim_value($ty_var.ty);)* |                 $(let $var = $var.to_sim_value_with_type($ty_var.ty);)* | ||||||
|                 ToSimValue::into_sim_value(($($var,)*), ty) |                 ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty) | ||||||
|             } |             } | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn into_sim_value(self, ty: Bundle) -> SimValue<Bundle> { |             fn into_sim_value_with_type(self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|                 #![allow(unused_mut)] |                 #![allow(unused_mut)] | ||||||
|                 #![allow(clippy::unused_unit)] |                 #![allow(clippy::unused_unit)] | ||||||
|                 let ($($var,)*) = self; |                 let ($($var,)*) = self; | ||||||
|  | @ -592,29 +592,44 @@ macro_rules! impl_tuples { | ||||||
|                     panic!("bundle has wrong number of fields"); |                     panic!("bundle has wrong number of fields"); | ||||||
|                 }; |                 }; | ||||||
|                 let mut bits = BitVec::new(); |                 let mut bits = BitVec::new(); | ||||||
|                 $(let $var = $var.into_sim_value($ty_var.ty); |                 $(let $var = $var.into_sim_value_with_type($ty_var.ty); | ||||||
|                 assert_eq!(SimValue::ty(&$var), $ty_var.ty); |                 assert_eq!(SimValue::ty(&$var), $ty_var.ty); | ||||||
|                 bits.extend_from_bitslice(SimValue::bits(&$var).bits()); |                 bits.extend_from_bitslice(SimValue::bits(&$var).bits()); | ||||||
|                 )* |                 )* | ||||||
|                 bits.into_sim_value(ty) |                 bits.into_sim_value_with_type(ty) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) { |         impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { |             fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||||
|                 let ($($var,)*) = self; |                 let ($($var,)*) = self; | ||||||
|                 let ($($ty_var,)*) = ty; |                 let ($($ty_var,)*) = ty; | ||||||
|                 $(let $var = $var.to_sim_value($ty_var);)* |                 $(let $var = $var.to_sim_value_with_type($ty_var);)* | ||||||
|                 SimValue::from_value(ty, ($($var,)*)) |                 SimValue::from_value(ty, ($($var,)*)) | ||||||
|             } |             } | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { |             fn into_sim_value_with_type(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||||
|                 let ($($var,)*) = self; |                 let ($($var,)*) = self; | ||||||
|                 let ($($ty_var,)*) = ty; |                 let ($($ty_var,)*) = ty; | ||||||
|                 $(let $var = $var.into_sim_value($ty_var);)* |                 $(let $var = $var.into_sim_value_with_type($ty_var);)* | ||||||
|                 SimValue::from_value(ty, ($($var,)*)) |                 SimValue::from_value(ty, ($($var,)*)) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { | ||||||
|  |             type Type = ($($T::Type,)*); | ||||||
|  |             #[track_caller] | ||||||
|  |             fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 $(let $var = $var.to_sim_value();)* | ||||||
|  |                 SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 $(let $var = $var.to_sim_value();)* | ||||||
|  |                 SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { |         impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { | ||||||
|             fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> { |             fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> { | ||||||
|                 let ($($lhs_var,)*) = *lhs; |                 let ($($lhs_var,)*) = *lhs; | ||||||
|  | @ -674,7 +689,7 @@ impl_tuples! { | ||||||
| impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | ||||||
|     type BaseType = Bundle; |     type BaseType = Bundle; | ||||||
|     type MaskType = (); |     type MaskType = (); | ||||||
|     type SimValue = (); |     type SimValue = PhantomData<T>; | ||||||
|     type MatchVariant = PhantomData<T>; |     type MatchVariant = PhantomData<T>; | ||||||
|     type MatchActiveScope = (); |     type MatchActiveScope = (); | ||||||
|     type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>; |     type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>; | ||||||
|  | @ -709,7 +724,7 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||||
|         assert!(bits.is_empty()); |         assert!(bits.is_empty()); | ||||||
|         () |         *self | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { | ||||||
|         assert!(bits.is_empty()); |         assert!(bits.is_empty()); | ||||||
|  | @ -764,26 +779,38 @@ impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: ?Sized + Send + Sync + 'static> ToSimValue<Self> for PhantomData<T> { | impl<T: ?Sized + Send + Sync + 'static> ToSimValue for PhantomData<T> { | ||||||
|  |     type Type = PhantomData<T>; | ||||||
|  | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: Self) -> SimValue<Self> { |     fn to_sim_value(&self) -> SimValue<Self> { | ||||||
|         ToSimValue::into_sim_value(BitVec::new(), ty) |         SimValue::from_value(*self, *self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: ?Sized> ToSimValue<Bundle> for PhantomData<T> { | impl<T: ?Sized + Send + Sync + 'static> ToSimValueWithType<Self> for PhantomData<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> { |     fn to_sim_value_with_type(&self, ty: Self) -> SimValue<Self> { | ||||||
|  |         SimValue::from_value(ty, *self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized> ToSimValueWithType<Bundle> for PhantomData<T> { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|         assert!(ty.fields().is_empty()); |         assert!(ty.fields().is_empty()); | ||||||
|         ToSimValue::into_sim_value(BitVec::new(), ty) |         ToSimValueWithType::into_sim_value_with_type(BitVec::new(), ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: ?Sized> ToSimValue<CanonicalType> for PhantomData<T> { | impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         let ty = Bundle::from_canonical(ty); |         let ty = Bundle::from_canonical(ty); | ||||||
|         assert!(ty.fields().is_empty()); |         assert!(ty.fields().is_empty()); | ||||||
|         SimValue::into_canonical(ToSimValue::into_sim_value(BitVec::new(), ty)) |         SimValue::into_canonical(ToSimValueWithType::into_sim_value_with_type( | ||||||
|  |             BitVec::new(), | ||||||
|  |             ty, | ||||||
|  |         )) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,12 +2,13 @@ | ||||||
| // See Notices.txt for copyright information
 | // See Notices.txt for copyright information
 | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     array::ArrayType, | ||||||
|     expr::{ |     expr::{ | ||||||
|         target::{GetTarget, Target}, |         target::{GetTarget, Target}, | ||||||
|         Expr, NotALiteralExpr, ToExpr, ToLiteralBits, |         Expr, NotALiteralExpr, ToExpr, ToLiteralBits, | ||||||
|     }, |     }, | ||||||
|     intern::{Intern, Interned, Memoize}, |     intern::{Intern, Interned, Memoize}, | ||||||
|     sim::value::SimValue, |     sim::value::{SimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, |     ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, | ||||||
|     util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, |     util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, | ||||||
|  | @ -58,7 +59,8 @@ pub trait KnownSize: | ||||||
|         + std::fmt::Debug |         + std::fmt::Debug | ||||||
|         + IntoIterator<Item = SimValue<Element>> |         + IntoIterator<Item = SimValue<Element>> | ||||||
|         + TryFrom<Vec<SimValue<Element>>> |         + TryFrom<Vec<SimValue<Element>>> | ||||||
|         + Into<Vec<SimValue<Element>>>; |         + Into<Vec<SimValue<Element>>> | ||||||
|  |         + ToSimValueWithType<ArrayType<Element, Self>>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| macro_rules! known_widths { | macro_rules! known_widths { | ||||||
|  | @ -120,7 +122,8 @@ pub trait Size: | ||||||
|         + std::fmt::Debug |         + std::fmt::Debug | ||||||
|         + IntoIterator<Item = SimValue<Element>> |         + IntoIterator<Item = SimValue<Element>> | ||||||
|         + TryFrom<Vec<SimValue<Element>>> |         + TryFrom<Vec<SimValue<Element>>> | ||||||
|         + Into<Vec<SimValue<Element>>>; |         + Into<Vec<SimValue<Element>>> | ||||||
|  |         + ToSimValueWithType<ArrayType<Element, Self>>; | ||||||
|     const KNOWN_VALUE: Option<usize>; |     const KNOWN_VALUE: Option<usize>; | ||||||
|     type SizeType: SizeType<Size = Self> |     type SizeType: SizeType<Size = Self> | ||||||
|         + Copy |         + Copy | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ use crate::{ | ||||||
|     }, |     }, | ||||||
|     int::Bool, |     int::Bool, | ||||||
|     intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize}, |     intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize}, | ||||||
|     sim::value::{SimValue, SimValuePartialEq}, |     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, |     ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, | ||||||
| }; | }; | ||||||
|  | @ -248,7 +248,7 @@ impl<T: ?Sized + PhantomConstValue> PhantomConst<T> { | ||||||
| impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> { | impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> { | ||||||
|     type BaseType = PhantomConst; |     type BaseType = PhantomConst; | ||||||
|     type MaskType = (); |     type MaskType = (); | ||||||
|     type SimValue = (); |     type SimValue = PhantomConst<T>; | ||||||
|     impl_match_variant_as_self!(); |     impl_match_variant_as_self!(); | ||||||
| 
 | 
 | ||||||
|     fn mask_type(&self) -> Self::MaskType { |     fn mask_type(&self) -> Self::MaskType { | ||||||
|  | @ -272,15 +272,17 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> { | ||||||
| 
 | 
 | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||||
|         assert!(bits.is_empty()); |         assert!(bits.is_empty()); | ||||||
|         () |         *self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||||
|         assert!(bits.is_empty()); |         assert!(bits.is_empty()); | ||||||
|  |         assert_eq!(*value, *self); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { | ||||||
|         assert!(bits.is_empty()); |         assert!(bits.is_empty()); | ||||||
|  |         assert_eq!(*value, *self); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -334,3 +336,23 @@ impl<T: ?Sized + PhantomConstValue> SimValuePartialEq<Self> for PhantomConst<T> | ||||||
|         true |         true | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized + PhantomConstValue> ToSimValue for PhantomConst<T> { | ||||||
|  |     type Type = PhantomConst<T>; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(*self, *self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<PhantomConst<T>> for PhantomConst<T> { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: PhantomConst<T>) -> SimValue<PhantomConst<T>> { | ||||||
|  |         SimValue::from_value(ty, *self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<CanonicalType> for PhantomConst<T> { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -7531,10 +7531,10 @@ macro_rules! impl_simulation_methods { | ||||||
|             SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) |             SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) | ||||||
|         } |         } | ||||||
|         $(#[$track_caller])? |         $(#[$track_caller])? | ||||||
|         pub $($async)? fn write<IO: Type, V: value::ToSimValue<IO>>(&mut $self, io: Expr<IO>, value: V) { |         pub $($async)? fn write<IO: Type, V: value::ToSimValueWithType<IO>>(&mut $self, io: Expr<IO>, value: V) { | ||||||
|             $self.sim_impl.borrow_mut().write( |             $self.sim_impl.borrow_mut().write( | ||||||
|                 Expr::canonical(io), |                 Expr::canonical(io), | ||||||
|                 &SimValue::into_canonical(value.into_sim_value(Expr::ty(io))), |                 &SimValue::into_canonical(value.into_sim_value_with_type(Expr::ty(io))), | ||||||
|                 $which_module, |                 $which_module, | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ use crate::{ | ||||||
|     expr::{CastBitsTo, Expr, ToExpr}, |     expr::{CastBitsTo, Expr, ToExpr}, | ||||||
|     int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, |     int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, | ||||||
|     reset::{AsyncReset, Reset, SyncReset}, |     reset::{AsyncReset, Reset, SyncReset}, | ||||||
|     ty::{CanonicalType, Type}, |     ty::{CanonicalType, StaticType, Type}, | ||||||
|     util::{ |     util::{ | ||||||
|         alternating_cell::{AlternatingCell, AlternatingCellMethods}, |         alternating_cell::{AlternatingCell, AlternatingCellMethods}, | ||||||
|         ConstUsize, |         ConstUsize, | ||||||
|  | @ -307,122 +307,223 @@ impl SimValuePartialEq<Bool> for Bool { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait ToSimValue<T: Type> { | pub trait ToSimValue: ToSimValueWithType<<Self as ToSimValue>::Type> { | ||||||
|  |     type Type: Type; | ||||||
|  | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T>; |     fn to_sim_value(&self) -> SimValue<Self::Type>; | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> |     fn into_sim_value(self) -> SimValue<Self::Type> | ||||||
|     where |     where | ||||||
|         Self: Sized, |         Self: Sized, | ||||||
|     { |     { | ||||||
|         self.to_sim_value(ty) |         self.to_sim_value() | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_into_sim_value(self: Arc<Self>, ty: T) -> SimValue<T> { |     fn arc_into_sim_value(self: Arc<Self>) -> SimValue<Self::Type> { | ||||||
|         self.to_sim_value(ty) |         self.to_sim_value() | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_to_sim_value(self: &Arc<Self>, ty: T) -> SimValue<T> { |     fn arc_to_sim_value(self: &Arc<Self>) -> SimValue<Self::Type> { | ||||||
|         self.to_sim_value(ty) |         self.to_sim_value() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> ToSimValue<T> for SimValue<T> { | pub trait ToSimValueWithType<T: Type> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T>; | ||||||
|         assert_eq!(SimValue::ty(self), ty); |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> | ||||||
|  |     where | ||||||
|  |         Self: Sized, | ||||||
|  |     { | ||||||
|  |         self.to_sim_value_with_type(ty) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> { | ||||||
|  |         self.to_sim_value_with_type(ty) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> { | ||||||
|  |         self.to_sim_value_with_type(ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | macro_rules! forward_to_sim_value_with_type { | ||||||
|  |     ([$($generics:tt)*] $ty:ty) => { | ||||||
|  |         impl<$($generics)*> ToSimValueWithType<<Self as ToSimValue>::Type> for $ty { | ||||||
|  |             fn to_sim_value_with_type(&self, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> { | ||||||
|  |                 let retval = Self::to_sim_value(self); | ||||||
|  |                 assert_eq!(SimValue::ty(&retval), ty); | ||||||
|  |                 retval | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn into_sim_value_with_type(self, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> | ||||||
|  |             where | ||||||
|  |                 Self: Sized, | ||||||
|  |             { | ||||||
|  |                 let retval = Self::into_sim_value(self); | ||||||
|  |                 assert_eq!(SimValue::ty(&retval), ty); | ||||||
|  |                 retval | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn arc_into_sim_value_with_type(self: Arc<Self>, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> { | ||||||
|  |                 let retval = Self::arc_into_sim_value(self); | ||||||
|  |                 assert_eq!(SimValue::ty(&retval), ty); | ||||||
|  |                 retval | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> { | ||||||
|  |                 let retval = Self::arc_to_sim_value(self); | ||||||
|  |                 assert_eq!(SimValue::ty(&retval), ty); | ||||||
|  |                 retval | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Type> ToSimValue for SimValue<T> { | ||||||
|  |     type Type = T; | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|         self.clone() |         self.clone() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { |  | ||||||
|         assert_eq!(SimValue::ty(&self), ty); |  | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> ToSimValue<T> for BitVec { | forward_to_sim_value_with_type!([T: Type] SimValue<T>); | ||||||
|  | 
 | ||||||
|  | impl<T: Type> ToSimValueWithType<T> for BitVec { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|         self.clone().into_sim_value(ty) |         self.clone().into_sim_value_with_type(ty) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||||
|         Arc::new(self).arc_into_sim_value(ty) |         Arc::new(self).arc_into_sim_value_with_type(ty) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_into_sim_value(self: Arc<Self>, ty: T) -> SimValue<T> { |     fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> { | ||||||
|         SimValue::from_bits(ty, UIntValue::new_dyn(self)) |         SimValue::from_bits(ty, UIntValue::new_dyn(self)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_to_sim_value(self: &Arc<Self>, ty: T) -> SimValue<T> { |     fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> { | ||||||
|         SimValue::from_bits(ty, UIntValue::new_dyn(self.clone())) |         SimValue::from_bits(ty, UIntValue::new_dyn(self.clone())) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> ToSimValue<T> for bitvec::boxed::BitBox { | impl<T: Type> ToSimValueWithType<T> for bitvec::boxed::BitBox { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|         self.clone().into_sim_value(ty) |         self.clone().into_sim_value_with_type(ty) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||||
|         self.into_bitvec().into_sim_value(ty) |         self.into_bitvec().into_sim_value_with_type(ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> ToSimValue<T> for BitSlice { | impl<T: Type> ToSimValueWithType<T> for BitSlice { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|         self.to_bitvec().into_sim_value(ty) |         self.to_bitvec().into_sim_value_with_type(ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for &'_ This { | impl<This: ?Sized + ToSimValue> ToSimValue for &'_ This { | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     type Type = This::Type; | ||||||
|         This::to_sim_value(self, ty) | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         This::to_sim_value(self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for &'_ mut This { | impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for &'_ This { | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|         This::to_sim_value(self, ty) |         This::to_sim_value_with_type(self, ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for Arc<This> { | impl<This: ?Sized + ToSimValue> ToSimValue for &'_ mut This { | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     type Type = This::Type; | ||||||
|         This::arc_to_sim_value(self, ty) | 
 | ||||||
|     } |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { |         This::to_sim_value(self) | ||||||
|         This::arc_into_sim_value(self, ty) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<This: ?Sized + ToSimValue<T> + Send + Sync + 'static, T: Type> ToSimValue<T> | impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for &'_ mut This { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|  |         This::to_sim_value_with_type(self, ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<This: ?Sized + ToSimValue> ToSimValue for Arc<This> { | ||||||
|  |     type Type = This::Type; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         This::arc_to_sim_value(self) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         This::arc_into_sim_value(self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for Arc<This> { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|  |         This::arc_to_sim_value_with_type(self, ty) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||||
|  |         This::arc_into_sim_value_with_type(self, ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<This: ?Sized + ToSimValue + Send + Sync + 'static> ToSimValue | ||||||
|     for crate::intern::Interned<This> |     for crate::intern::Interned<This> | ||||||
| { | { | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     type Type = This::Type; | ||||||
|         This::to_sim_value(self, ty) |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         This::to_sim_value(self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<This: ToSimValue<T>, T: Type> ToSimValue<T> for Box<This> { | impl<This: ?Sized + ToSimValueWithType<T> + Send + Sync + 'static, T: Type> ToSimValueWithType<T> | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     for crate::intern::Interned<This> | ||||||
|         This::to_sim_value(self, ty) | { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|  |         This::to_sim_value_with_type(self, ty) | ||||||
|     } |     } | ||||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { | } | ||||||
|         This::into_sim_value(*self, ty) | 
 | ||||||
|  | impl<This: ToSimValue> ToSimValue for Box<This> { | ||||||
|  |     type Type = This::Type; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         This::to_sim_value(self) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         This::into_sim_value(*self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<This: ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for Box<This> { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|  |         This::to_sim_value_with_type(self, ty) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||||
|  |         This::into_sim_value_with_type(*self, ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type, Len: Size> SimValue<ArrayType<T, Len>> { | impl<T: Type, Len: Size> SimValue<ArrayType<T, Len>> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_array_elements<I: IntoIterator<Item: ToSimValue<T>>>( |     pub fn from_array_elements<I: IntoIterator<Item: ToSimValueWithType<T>>>( | ||||||
|         ty: ArrayType<T, Len>, |         ty: ArrayType<T, Len>, | ||||||
|         elements: I, |         elements: I, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|  | @ -430,23 +531,32 @@ impl<T: Type, Len: Size> SimValue<ArrayType<T, Len>> { | ||||||
|         let elements = Vec::from_iter( |         let elements = Vec::from_iter( | ||||||
|             elements |             elements | ||||||
|                 .into_iter() |                 .into_iter() | ||||||
|                 .map(|element| element.into_sim_value(element_ty)), |                 .map(|element| element.into_sim_value_with_type(element_ty)), | ||||||
|         ); |         ); | ||||||
|         assert_eq!(elements.len(), ty.len()); |         assert_eq!(elements.len(), ty.len()); | ||||||
|         SimValue::from_value(ty, elements.try_into().ok().expect("already checked len")) |         SimValue::from_value(ty, elements.try_into().ok().expect("already checked len")) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<T>, T: Type> ToSimValue<Array<T>> for [Element] { | impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for [Element] { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> { |     fn to_sim_value_with_type(&self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(ty, self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for [Element] { | impl<Element: ToSimValue<Type: StaticType>> ToSimValue for [Element] { | ||||||
|  |     type Type = Array<Element::Type>; | ||||||
|  | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValueWithType<CanonicalType>> ToSimValueWithType<CanonicalType> for [Element] { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         SimValue::into_canonical(SimValue::from_array_elements( |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|             <Array>::from_canonical(ty), |             <Array>::from_canonical(ty), | ||||||
|             self, |             self, | ||||||
|  | @ -454,71 +564,61 @@ impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for [Element] | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<T>, T: Type, const N: usize> ToSimValue<Array<T, N>> for [Element; N] | impl<Element: ToSimValueWithType<T>, T: Type, const N: usize> ToSimValueWithType<Array<T, N>> | ||||||
|  |     for [Element; N] | ||||||
| where | where | ||||||
|     ConstUsize<N>: KnownSize, |     ConstUsize<N>: KnownSize, | ||||||
| { | { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: Array<T, N>) -> SimValue<Array<T, N>> { |     fn to_sim_value_with_type(&self, ty: Array<T, N>) -> SimValue<Array<T, N>> { | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(ty, self) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: Array<T, N>) -> SimValue<Array<T, N>> { |     fn into_sim_value_with_type(self, ty: Array<T, N>) -> SimValue<Array<T, N>> { | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(ty, self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<T>, T: Type, const N: usize> ToSimValue<Array<T>> for [Element; N] { | impl<Element: ToSimValue<Type: StaticType>, const N: usize> ToSimValue for [Element; N] | ||||||
|     #[track_caller] | where | ||||||
|     fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> { |     ConstUsize<N>: KnownSize, | ||||||
|         SimValue::from_array_elements(ty, self) | { | ||||||
|  |     type Type = Array<Element::Type, N>; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(StaticType::TYPE, self) | ||||||
|     } |     } | ||||||
|     #[track_caller] | 
 | ||||||
|     fn into_sim_value(self, ty: Array<T>) -> SimValue<Array<T>> { |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(StaticType::TYPE, self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<CanonicalType>, const N: usize> ToSimValue<CanonicalType> | impl<Element: ToSimValueWithType<T>, T: Type, const N: usize> ToSimValueWithType<Array<T>> | ||||||
|     for [Element; N] |     for [Element; N] | ||||||
| { | { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value_with_type(&self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|         SimValue::into_canonical(SimValue::from_array_elements( |  | ||||||
|             <Array>::from_canonical(ty), |  | ||||||
|             self, |  | ||||||
|         )) |  | ||||||
|     } |  | ||||||
|     #[track_caller] |  | ||||||
|     fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> { |  | ||||||
|         SimValue::into_canonical(SimValue::from_array_elements( |  | ||||||
|             <Array>::from_canonical(ty), |  | ||||||
|             self, |  | ||||||
|         )) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<Element: ToSimValue<T>, T: Type> ToSimValue<Array<T>> for Vec<Element> { |  | ||||||
|     #[track_caller] |  | ||||||
|     fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> { |  | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(ty, self) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: Array<T>) -> SimValue<Array<T>> { |     fn into_sim_value_with_type(self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|         SimValue::from_array_elements(ty, self) |         SimValue::from_array_elements(ty, self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for Vec<Element> { | impl<Element: ToSimValueWithType<CanonicalType>, const N: usize> ToSimValueWithType<CanonicalType> | ||||||
|  |     for [Element; N] | ||||||
|  | { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         SimValue::into_canonical(SimValue::from_array_elements( |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|             <Array>::from_canonical(ty), |             <Array>::from_canonical(ty), | ||||||
|             self, |             self, | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         SimValue::into_canonical(SimValue::from_array_elements( |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|             <Array>::from_canonical(ty), |             <Array>::from_canonical(ty), | ||||||
|             self, |             self, | ||||||
|  | @ -526,37 +626,131 @@ impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for Vec<Eleme | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> ToSimValue<T> for Expr<T> { | impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for Vec<Element> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { |     fn to_sim_value_with_type(&self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|         assert_eq!(Expr::ty(*self), ty); |         SimValue::from_array_elements(ty, self) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|  |         SimValue::from_array_elements(ty, self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValue<Type: StaticType>> ToSimValue for Vec<Element> { | ||||||
|  |     type Type = Array<Element::Type>; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValueWithType<CanonicalType>> ToSimValueWithType<CanonicalType> | ||||||
|  |     for Vec<Element> | ||||||
|  | { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|  |             <Array>::from_canonical(ty), | ||||||
|  |             self, | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|  |             <Array>::from_canonical(ty), | ||||||
|  |             self, | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for Box<[Element]> { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|  |         SimValue::from_array_elements(ty, self) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: Array<T>) -> SimValue<Array<T>> { | ||||||
|  |         SimValue::from_array_elements(ty, self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValue<Type: StaticType>> ToSimValue for Box<[Element]> { | ||||||
|  |     type Type = Array<Element::Type>; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Element: ToSimValueWithType<CanonicalType>> ToSimValueWithType<CanonicalType> | ||||||
|  |     for Box<[Element]> | ||||||
|  | { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|  |             <Array>::from_canonical(ty), | ||||||
|  |             self, | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         SimValue::into_canonical(SimValue::from_array_elements( | ||||||
|  |             <Array>::from_canonical(ty), | ||||||
|  |             self, | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Type> ToSimValue for Expr<T> { | ||||||
|  |     type Type = T; | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|         SimValue::from_bitslice( |         SimValue::from_bitslice( | ||||||
|             ty, |             Expr::ty(*self), | ||||||
|             &crate::expr::ToLiteralBits::to_literal_bits(self) |             &crate::expr::ToLiteralBits::to_literal_bits(self) | ||||||
|                 .expect("must be a literal expression"), |                 .expect("must be a literal expression"), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | forward_to_sim_value_with_type!([T: Type] Expr<T>); | ||||||
|  | 
 | ||||||
| macro_rules! impl_to_sim_value_for_bool_like { | macro_rules! impl_to_sim_value_for_bool_like { | ||||||
|     ($ty:ident) => { |     ($ty:ident) => { | ||||||
|         impl ToSimValue<$ty> for bool { |         impl ToSimValueWithType<$ty> for bool { | ||||||
|             fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> { |             fn to_sim_value_with_type(&self, ty: $ty) -> SimValue<$ty> { | ||||||
|                 SimValue::from_value(ty, *self) |                 SimValue::from_value(ty, *self) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl ToSimValue for bool { | ||||||
|  |     type Type = Bool; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(Bool, *self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl_to_sim_value_for_bool_like!(Bool); | impl_to_sim_value_for_bool_like!(Bool); | ||||||
| impl_to_sim_value_for_bool_like!(AsyncReset); | impl_to_sim_value_for_bool_like!(AsyncReset); | ||||||
| impl_to_sim_value_for_bool_like!(SyncReset); | impl_to_sim_value_for_bool_like!(SyncReset); | ||||||
| impl_to_sim_value_for_bool_like!(Reset); | impl_to_sim_value_for_bool_like!(Reset); | ||||||
| impl_to_sim_value_for_bool_like!(Clock); | impl_to_sim_value_for_bool_like!(Clock); | ||||||
| 
 | 
 | ||||||
| impl ToSimValue<CanonicalType> for bool { | impl ToSimValueWithType<CanonicalType> for bool { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         match ty { |         match ty { | ||||||
|             CanonicalType::UInt(_) |             CanonicalType::UInt(_) | ||||||
|             | CanonicalType::SInt(_) |             | CanonicalType::SInt(_) | ||||||
|  | @ -579,19 +773,22 @@ impl ToSimValue<CanonicalType> for bool { | ||||||
| 
 | 
 | ||||||
| macro_rules! impl_to_sim_value_for_primitive_int { | macro_rules! impl_to_sim_value_for_primitive_int { | ||||||
|     ($prim:ident) => { |     ($prim:ident) => { | ||||||
|         impl ToSimValue<<$prim as ToExpr>::Type> for $prim { |         impl ToSimValue for $prim { | ||||||
|  |             type Type = <$prim as ToExpr>::Type; | ||||||
|  | 
 | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value( |             fn to_sim_value( | ||||||
|                 &self, |                 &self, | ||||||
|                 ty: <$prim as ToExpr>::Type, |             ) -> SimValue<Self::Type> { | ||||||
|             ) -> SimValue<<$prim as ToExpr>::Type> { |                 SimValue::from_value(StaticType::TYPE, (*self).into()) | ||||||
|                 SimValue::from_value(ty, (*self).into()) |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl ToSimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { |         forward_to_sim_value_with_type!([] $prim); | ||||||
|  | 
 | ||||||
|  |         impl ToSimValueWithType<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value( |             fn to_sim_value_with_type( | ||||||
|                 &self, |                 &self, | ||||||
|                 ty: <<$prim as ToExpr>::Type as IntType>::Dyn, |                 ty: <<$prim as ToExpr>::Type as IntType>::Dyn, | ||||||
|             ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { |             ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { | ||||||
|  | @ -602,11 +799,11 @@ macro_rules! impl_to_sim_value_for_primitive_int { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl ToSimValue<CanonicalType> for $prim { |         impl ToSimValueWithType<CanonicalType> for $prim { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |             fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|                 let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); |                 let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); | ||||||
|                 SimValue::into_canonical(self.to_sim_value(ty)) |                 SimValue::into_canonical(self.to_sim_value_with_type(ty)) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  | @ -627,35 +824,51 @@ impl_to_sim_value_for_primitive_int!(isize); | ||||||
| 
 | 
 | ||||||
| macro_rules! impl_to_sim_value_for_int_value { | macro_rules! impl_to_sim_value_for_int_value { | ||||||
|     ($IntValue:ident, $Int:ident, $IntType:ident) => { |     ($IntValue:ident, $Int:ident, $IntType:ident) => { | ||||||
|         impl<Width: KnownSize> ToSimValue<$IntType<Width>> for $IntValue<Width> { |         impl<Width: Size> ToSimValue for $IntValue<Width> { | ||||||
|             fn to_sim_value(&self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { |             type Type = $IntType<Width>; | ||||||
|                 self.bits().to_sim_value(ty) | 
 | ||||||
|  |             fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |                 SimValue::from_value(self.ty(), self.clone()) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn into_sim_value(self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { |             fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|                 self.into_bits().into_sim_value(ty) |                 SimValue::from_value(self.ty(), self) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl<Width: Size> ToSimValue<$Int> for $IntValue<Width> { |         impl<Width: Size> ToSimValueWithType<$IntType<Width>> for $IntValue<Width> { | ||||||
|             fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> { |             fn to_sim_value_with_type(&self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { | ||||||
|                 self.bits().to_sim_value(ty) |                 SimValue::from_value(ty, self.clone()) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn into_sim_value(self, ty: $Int) -> SimValue<$Int> { |             fn into_sim_value_with_type(self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { | ||||||
|                 self.into_bits().into_sim_value(ty) |                 SimValue::from_value(ty, self) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl<Width: Size> ToSimValue<CanonicalType> for $IntValue<Width> { |         impl<Width: KnownSize> ToSimValueWithType<$Int> for $IntValue<Width> { | ||||||
|  |             fn to_sim_value_with_type(&self, ty: $Int) -> SimValue<$Int> { | ||||||
|  |                 self.bits().to_sim_value_with_type(ty) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             fn into_sim_value_with_type(self, ty: $Int) -> SimValue<$Int> { | ||||||
|  |                 self.into_bits().into_sim_value_with_type(ty) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         impl<Width: Size> ToSimValueWithType<CanonicalType> for $IntValue<Width> { | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |             fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|                 SimValue::into_canonical(self.to_sim_value($Int::from_canonical(ty))) |                 SimValue::into_canonical( | ||||||
|  |                     self.to_sim_value_with_type($IntType::<Width>::from_canonical(ty)), | ||||||
|  |                 ) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[track_caller] |             #[track_caller] | ||||||
|             fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> { |             fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|                 SimValue::into_canonical(self.into_sim_value($Int::from_canonical(ty))) |                 SimValue::into_canonical( | ||||||
|  |                     self.into_sim_value_with_type($IntType::<Width>::from_canonical(ty)), | ||||||
|  |                 ) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ use crate::{ | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|     phantom_const::PhantomConst, |     phantom_const::PhantomConst, | ||||||
|     reset::{AsyncReset, Reset, SyncReset}, |     reset::{AsyncReset, Reset, SyncReset}, | ||||||
|  |     sim::value::{SimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     util::ConstUsize, |     util::ConstUsize, | ||||||
| }; | }; | ||||||
|  | @ -269,7 +270,7 @@ pub trait Type: | ||||||
| { | { | ||||||
|     type BaseType: BaseType; |     type BaseType: BaseType; | ||||||
|     type MaskType: Type<MaskType = Self::MaskType>; |     type MaskType: Type<MaskType = Self::MaskType>; | ||||||
|     type SimValue: fmt::Debug + Clone + 'static; |     type SimValue: fmt::Debug + Clone + 'static + ToSimValueWithType<Self>; | ||||||
|     type MatchVariant: 'static + Send + Sync; |     type MatchVariant: 'static + Send + Sync; | ||||||
|     type MatchActiveScope; |     type MatchActiveScope; | ||||||
|     type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< |     type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< | ||||||
|  | @ -389,6 +390,15 @@ impl OpaqueSimValue { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValue { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||||
|  |         SimValue::from_value(ty, self.clone()) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||||
|  |         SimValue::from_value(ty, self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub trait StaticType: Type { | pub trait StaticType: Type { | ||||||
|     const TYPE: Self; |     const TYPE: Self; | ||||||
|     const MASK_TYPE: Self::MaskType; |     const MASK_TYPE: Self::MaskType; | ||||||
|  |  | ||||||
|  | @ -7,13 +7,7 @@ use fayalite::{ | ||||||
|     module::{instance_with_loc, reg_builder_with_loc}, |     module::{instance_with_loc, reg_builder_with_loc}, | ||||||
|     prelude::*, |     prelude::*, | ||||||
|     reset::ResetType, |     reset::ResetType, | ||||||
|     sim::{ |     sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation}, | ||||||
|         time::SimDuration, |  | ||||||
|         value::{SimValue, ToSimValue}, |  | ||||||
|         vcd::VcdWriterDecls, |  | ||||||
|         Simulation, |  | ||||||
|     }, |  | ||||||
|     ty::StaticType, |  | ||||||
|     util::RcWriter, |     util::RcWriter, | ||||||
| }; | }; | ||||||
| use std::num::NonZeroUsize; | use std::num::NonZeroUsize; | ||||||
|  | @ -391,113 +385,110 @@ fn test_enums() { | ||||||
|     let mut sim = Simulation::new(enums()); |     let mut sim = Simulation::new(enums()); | ||||||
|     let mut writer = RcWriter::default(); |     let mut writer = RcWriter::default(); | ||||||
|     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); |     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); | ||||||
|     sim.write_clock(sim.io().cd.clk, false); |     sim.write(sim.io().cd.clk, false); | ||||||
|     sim.write_reset(sim.io().cd.rst, true); |     sim.write(sim.io().cd.rst, true); | ||||||
|     sim.write_bool(sim.io().en, false); |     sim.write(sim.io().en, false); | ||||||
|     sim.write_bool_or_int(sim.io().which_in, 0_hdl_u2); |     sim.write(sim.io().which_in, 0_hdl_u2); | ||||||
|     sim.write_bool_or_int(sim.io().data_in, 0_hdl_u4); |     sim.write(sim.io().data_in, 0_hdl_u4); | ||||||
|     sim.advance_time(SimDuration::from_micros(1)); |     sim.advance_time(SimDuration::from_micros(1)); | ||||||
|     sim.write_clock(sim.io().cd.clk, true); |     sim.write(sim.io().cd.clk, true); | ||||||
|     sim.advance_time(SimDuration::from_nanos(100)); |     sim.advance_time(SimDuration::from_nanos(100)); | ||||||
|     sim.write_reset(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)); | ||||||
|     type BOutTy = HdlOption<(UInt<1>, Bool)>; |     #[hdl(cmp_eq)] | ||||||
|     #[derive(Debug, PartialEq)] |  | ||||||
|     struct IO { |     struct IO { | ||||||
|         en: bool, |         en: Bool, | ||||||
|         which_in: u8, |         which_in: UInt<2>, | ||||||
|         data_in: u8, |         data_in: UInt<4>, | ||||||
|         which_out: u8, |         which_out: UInt<2>, | ||||||
|         data_out: u8, |         data_out: UInt<4>, | ||||||
|         b_out: SimValue<BOutTy>, |         b_out: HdlOption<(UInt<1>, Bool)>, | ||||||
|     } |     } | ||||||
|     let io_cycles = [ |     let io_cycles = [ | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: false, |             en: false, | ||||||
|             which_in: 0, |             which_in: 0_hdl_u2, | ||||||
|             data_in: 0, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 0, |             which_out: 0_hdl_u2, | ||||||
|             data_out: 0, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 0, |             which_out: 0_hdl_u2, | ||||||
|             data_out: 0, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: false, |             en: false, | ||||||
|             which_in: 0, |             which_in: 0_hdl_u2, | ||||||
|             data_in: 0, |             data_in: 0_hdl_u4, | ||||||
|             which_out: 1, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), |             b_out: HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0xF, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0, |             data_out: 0_hdl_u4, | ||||||
|             b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), |             b_out: HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 1, |             which_in: 1_hdl_u2, | ||||||
|             data_in: 0xF, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0x3, |             data_out: 0x3_hdl_u4, | ||||||
|             b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), |             b_out: HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 2, |             which_in: 2_hdl_u2, | ||||||
|             data_in: 0xF, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 1, |             which_out: 1_hdl_u2, | ||||||
|             data_out: 0x3, |             data_out: 0x3_hdl_u4, | ||||||
|             b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), |             b_out: HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|  |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|             which_in: 2, |             which_in: 2_hdl_u2, | ||||||
|             data_in: 0xF, |             data_in: 0xF_hdl_u4, | ||||||
|             which_out: 2, |             which_out: 2_hdl_u2, | ||||||
|             data_out: 0xF, |             data_out: 0xF_hdl_u4, | ||||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|     ]; |     ]; | ||||||
|     for ( |     for (cycle, expected) in io_cycles.into_iter().enumerate() { | ||||||
|         cycle, |         #[hdl(sim)] | ||||||
|         expected @ 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: _, | ||||||
|         }, |         } = expected; | ||||||
|     ) in io_cycles.into_iter().enumerate() |         sim.write(sim.io().en, &en); | ||||||
|     { |         sim.write(sim.io().which_in, &which_in); | ||||||
|         sim.write_bool(sim.io().en, en); |         sim.write(sim.io().data_in, &data_in); | ||||||
|         sim.write_bool_or_int(sim.io().which_in, which_in.cast_to_static()); |         let io = #[hdl(sim)] | ||||||
|         sim.write_bool_or_int(sim.io().data_in, data_in.cast_to_static()); |         IO { | ||||||
|         let io = IO { |  | ||||||
|             en, |             en, | ||||||
|             which_in, |             which_in, | ||||||
|             data_in, |             data_in, | ||||||
|             which_out: sim |             which_out: sim.read(sim.io().which_out), | ||||||
|                 .read_bool_or_int(sim.io().which_out) |             data_out: sim.read(sim.io().data_out), | ||||||
|                 .to_bigint() |  | ||||||
|                 .try_into() |  | ||||||
|                 .expect("known to be in range"), |  | ||||||
|             data_out: sim |  | ||||||
|                 .read_bool_or_int(sim.io().data_out) |  | ||||||
|                 .to_bigint() |  | ||||||
|                 .try_into() |  | ||||||
|                 .expect("known to be in range"), |  | ||||||
|             b_out: sim.read(sim.io().b_out), |             b_out: sim.read(sim.io().b_out), | ||||||
|         }; |         }; | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|  | @ -559,7 +550,7 @@ fn test_memories() { | ||||||
|         w_mask: (Bool, Bool), |         w_mask: (Bool, Bool), | ||||||
|     } |     } | ||||||
|     let io_cycles = [ |     let io_cycles = [ | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: false, |             r_en: false, | ||||||
|  | @ -569,7 +560,7 @@ fn test_memories() { | ||||||
|             w_data: (0u8, 0i8), |             w_data: (0u8, 0i8), | ||||||
|             w_mask: (false, false), |             w_mask: (false, false), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -579,7 +570,7 @@ fn test_memories() { | ||||||
|             w_data: (0x10u8, 0x20i8), |             w_data: (0x10u8, 0x20i8), | ||||||
|             w_mask: (true, true), |             w_mask: (true, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -589,7 +580,7 @@ fn test_memories() { | ||||||
|             w_data: (0x30u8, 0x40i8), |             w_data: (0x30u8, 0x40i8), | ||||||
|             w_mask: (false, true), |             w_mask: (false, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -599,7 +590,7 @@ fn test_memories() { | ||||||
|             w_data: (0x50u8, 0x60i8), |             w_data: (0x50u8, 0x60i8), | ||||||
|             w_mask: (true, false), |             w_mask: (true, false), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -609,7 +600,7 @@ fn test_memories() { | ||||||
|             w_data: (0x70u8, -0x80i8), |             w_data: (0x70u8, -0x80i8), | ||||||
|             w_mask: (false, false), |             w_mask: (false, false), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -619,7 +610,7 @@ fn test_memories() { | ||||||
|             w_data: (0x90u8, 0xA0u8 as i8), |             w_data: (0x90u8, 0xA0u8 as i8), | ||||||
|             w_mask: (false, false), |             w_mask: (false, false), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -629,7 +620,7 @@ fn test_memories() { | ||||||
|             w_data: (0x90u8, 0xA0u8 as i8), |             w_data: (0x90u8, 0xA0u8 as i8), | ||||||
|             w_mask: (true, true), |             w_mask: (true, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -639,7 +630,7 @@ fn test_memories() { | ||||||
|             w_data: (0xB0u8, 0xC0u8 as i8), |             w_data: (0xB0u8, 0xC0u8 as i8), | ||||||
|             w_mask: (true, true), |             w_mask: (true, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 0_hdl_u4, |             r_addr: 0_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -649,7 +640,7 @@ fn test_memories() { | ||||||
|             w_data: (0xD0u8, 0xE0u8 as i8), |             w_data: (0xD0u8, 0xE0u8 as i8), | ||||||
|             w_mask: (true, true), |             w_mask: (true, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 1_hdl_u4, |             r_addr: 1_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -659,7 +650,7 @@ fn test_memories() { | ||||||
|             w_data: (0xD0u8, 0xE0u8 as i8), |             w_data: (0xD0u8, 0xE0u8 as i8), | ||||||
|             w_mask: (true, true), |             w_mask: (true, true), | ||||||
|         }, |         }, | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr: 2_hdl_u4, |             r_addr: 2_hdl_u4, | ||||||
|             r_en: true, |             r_en: true, | ||||||
|  | @ -671,7 +662,7 @@ fn test_memories() { | ||||||
|         }, |         }, | ||||||
|     ]; |     ]; | ||||||
|     for (cycle, expected) in io_cycles.into_iter().enumerate() { |     for (cycle, expected) in io_cycles.into_iter().enumerate() { | ||||||
|         #[hdl] |         #[hdl(sim)] | ||||||
|         let IO { |         let IO { | ||||||
|             r_addr, |             r_addr, | ||||||
|             r_en, |             r_en, | ||||||
|  | @ -681,13 +672,13 @@ fn test_memories() { | ||||||
|             w_data, |             w_data, | ||||||
|             w_mask, |             w_mask, | ||||||
|         } = expected; |         } = expected; | ||||||
|         sim.write(sim.io().r.addr, r_addr); |         sim.write(sim.io().r.addr, &r_addr); | ||||||
|         sim.write(sim.io().r.en, r_en); |         sim.write(sim.io().r.en, &r_en); | ||||||
|         sim.write(sim.io().w.addr, w_addr); |         sim.write(sim.io().w.addr, &w_addr); | ||||||
|         sim.write(sim.io().w.en, w_en); |         sim.write(sim.io().w.en, &w_en); | ||||||
|         sim.write(sim.io().w.data, w_data); |         sim.write(sim.io().w.data, &w_data); | ||||||
|         sim.write(sim.io().w.mask, w_mask); |         sim.write(sim.io().w.mask, &w_mask); | ||||||
|         let io = (#[hdl] |         let io = #[hdl(sim)] | ||||||
|         IO { |         IO { | ||||||
|             r_addr, |             r_addr, | ||||||
|             r_en, |             r_en, | ||||||
|  | @ -696,20 +687,19 @@ fn test_memories() { | ||||||
|             w_en, |             w_en, | ||||||
|             w_data, |             w_data, | ||||||
|             w_mask, |             w_mask, | ||||||
|         }) |         }; | ||||||
|         .to_sim_value(StaticType::TYPE); |  | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             expected.to_sim_value(StaticType::TYPE), |             expected, | ||||||
|             io, |             io, | ||||||
|             "vcd:\n{}\ncycle: {cycle}", |             "vcd:\n{}\ncycle: {cycle}", | ||||||
|             String::from_utf8(writer.take()).unwrap(), |             String::from_utf8(writer.take()).unwrap(), | ||||||
|         ); |         ); | ||||||
|         sim.advance_time(SimDuration::from_micros(1)); |         sim.advance_time(SimDuration::from_micros(1)); | ||||||
|         sim.write_clock(sim.io().r.clk, true); |         sim.write(sim.io().r.clk, true); | ||||||
|         sim.write_clock(sim.io().w.clk, true); |         sim.write(sim.io().w.clk, true); | ||||||
|         sim.advance_time(SimDuration::from_micros(1)); |         sim.advance_time(SimDuration::from_micros(1)); | ||||||
|         sim.write_clock(sim.io().r.clk, false); |         sim.write(sim.io().r.clk, false); | ||||||
|         sim.write_clock(sim.io().w.clk, false); |         sim.write(sim.io().w.clk, false); | ||||||
|     } |     } | ||||||
|     sim.flush_traces().unwrap(); |     sim.flush_traces().unwrap(); | ||||||
|     let vcd = String::from_utf8(writer.take()).unwrap(); |     let vcd = String::from_utf8(writer.take()).unwrap(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue