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); | ||||
|             } | ||||
|         })); | ||||
|         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(); | ||||
|         quote_spanned! {span=> | ||||
|             #[automatically_derived] | ||||
|  | @ -797,6 +803,51 @@ impl ToTokens for ParsedBundle { | |||
|                 } | ||||
|             } | ||||
|             #[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 | ||||
|             #where_clause | ||||
|             { | ||||
|  | @ -900,6 +951,51 @@ impl ToTokens for ParsedBundle { | |||
|                     ::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); | ||||
|         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); | ||||
|         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 = | ||||
|                         <::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); | ||||
|         } | ||||
|  |  | |||
|  | @ -93,6 +93,7 @@ mod kw { | |||
|     custom_keyword!(output); | ||||
|     custom_keyword!(reg_builder); | ||||
|     custom_keyword!(reset); | ||||
|     custom_keyword!(sim); | ||||
|     custom_keyword!(skip); | ||||
|     custom_keyword!(target); | ||||
|     custom_keyword!(wire); | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ use std::{borrow::Borrow, convert::Infallible}; | |||
| use syn::{ | ||||
|     fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold}, | ||||
|     parenthesized, | ||||
|     parse::{Nothing, Parse, ParseStream}, | ||||
|     parse::{Parse, ParseStream}, | ||||
|     parse_quote, parse_quote_spanned, | ||||
|     spanned::Spanned, | ||||
|     token::Paren, | ||||
|  | @ -27,6 +27,13 @@ use syn::{ | |||
| mod expand_aggregate_literals; | ||||
| mod expand_match; | ||||
| 
 | ||||
| options! { | ||||
|     #[options = ExprOptions] | ||||
|     pub(crate) enum ExprOption { | ||||
|         Sim(sim), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| options! { | ||||
|     pub(crate) enum LetFnKind { | ||||
|         Input(input), | ||||
|  | @ -952,7 +959,7 @@ with_debug_clone_and_fold! { | |||
|     #[allow(dead_code)] | ||||
|     pub(crate) struct HdlLet<Kind = HdlLetKind> { | ||||
|         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) mut_token: Option<Token![mut]>, | ||||
|         pub(crate) name: Ident, | ||||
|  | @ -1173,7 +1180,7 @@ impl Visitor<'_> { | |||
|             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 { | ||||
|             attrs, | ||||
|             if_token, | ||||
|  | @ -1181,10 +1188,10 @@ impl Visitor<'_> { | |||
|             then_branch, | ||||
|             else_branch, | ||||
|         } = expr_if; | ||||
|         self.require_normal_module_or_fn(if_token); | ||||
|         let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr { | ||||
|             Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if), | ||||
|             expr => expr, | ||||
|         let (else_token, else_expr) = else_branch.unzip(); | ||||
|         let else_expr = else_expr.map(|else_expr| match *else_expr { | ||||
|             Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)), | ||||
|             _ => else_expr, | ||||
|         }); | ||||
|         if let Expr::Let(ExprLet { | ||||
|             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=> | ||||
|                 #(#attrs)* | ||||
|                 { | ||||
|  | @ -1675,7 +1694,7 @@ impl Fold for Visitor<'_> { | |||
|     fn fold_local(&mut self, mut let_stmt: Local) -> Local { | ||||
|         match self | ||||
|             .errors | ||||
|             .ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr( | ||||
|             .ok(HdlAttr::<ExprOptions, kw::hdl>::parse_and_leave_attr( | ||||
|                 &let_stmt.attrs, | ||||
|             )) { | ||||
|             None => return empty_let(), | ||||
|  | @ -1694,7 +1713,8 @@ impl Fold for Visitor<'_> { | |||
|             subpat: None, | ||||
|         }) = pat | ||||
|         else { | ||||
|             let hdl_attr = HdlAttr::<Nothing, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs) | ||||
|             let hdl_attr = | ||||
|                 HdlAttr::<ExprOptions, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs) | ||||
|                     .ok() | ||||
|                     .flatten() | ||||
|                     .expect("already checked above"); | ||||
|  |  | |||
|  | @ -1,45 +1,97 @@ | |||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||
| // 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 syn::{ | ||||
|     parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, | ||||
|     ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath, | ||||
|     parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, ExprRepeat, ExprStruct, | ||||
|     ExprTuple, FieldValue, TypePath, | ||||
| }; | ||||
| 
 | ||||
| impl Visitor<'_> { | ||||
|     pub(crate) fn process_hdl_array( | ||||
|         &mut self, | ||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         mut expr_array: ExprArray, | ||||
|     ) -> Expr { | ||||
|         self.require_normal_module_or_fn(hdl_attr); | ||||
|         let ExprOptions { sim } = hdl_attr.body; | ||||
|         let span = hdl_attr.kw.span; | ||||
|         if sim.is_some() { | ||||
|             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! {::fayalite::expr::ToExpr::to_expr(&#expr_array)} | ||||
|             parse_quote_spanned! {span=> | ||||
|                 ::fayalite::expr::ToExpr::to_expr(&#expr_array) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     pub(crate) fn process_hdl_repeat( | ||||
|         &mut self, | ||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         mut expr_repeat: ExprRepeat, | ||||
|     ) -> Expr { | ||||
|         self.require_normal_module_or_fn(hdl_attr); | ||||
|         let repeated_value = &expr_repeat.expr; | ||||
|         let ExprOptions { sim } = hdl_attr.body; | ||||
|         let span = hdl_attr.kw.span; | ||||
|         if sim.is_some() { | ||||
|             *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! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)} | ||||
|             parse_quote_spanned! {span=> | ||||
|                 ::fayalite::expr::ToExpr::to_expr(&#expr_repeat) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     pub(crate) fn process_hdl_struct( | ||||
|         &mut self, | ||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         expr_struct: ExprStruct, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         mut expr_struct: ExprStruct, | ||||
|     ) -> Expr { | ||||
|         self.require_normal_module_or_fn(&hdl_attr); | ||||
|         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 empty_builder = if expr_struct.qself.is_some() | ||||
|             || expr_struct | ||||
|  | @ -91,12 +143,23 @@ impl Visitor<'_> { | |||
|     } | ||||
|     pub(crate) fn process_hdl_tuple( | ||||
|         &mut self, | ||||
|         hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         expr_tuple: ExprTuple, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         mut expr_tuple: ExprTuple, | ||||
|     ) -> Expr { | ||||
|         self.require_normal_module_or_fn(hdl_attr); | ||||
|         let ExprOptions { sim } = hdl_attr.body; | ||||
|         if sim.is_some() { | ||||
|             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::{ | ||||
|     fold::{impl_fold, DoFold}, | ||||
|     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, | ||||
| }; | ||||
| use proc_macro2::{Span, TokenStream}; | ||||
|  | @ -11,7 +13,6 @@ use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt}; | |||
| use std::collections::BTreeSet; | ||||
| use syn::{ | ||||
|     fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold}, | ||||
|     parse::Nothing, | ||||
|     parse_quote_spanned, | ||||
|     punctuated::Punctuated, | ||||
|     spanned::Spanned, | ||||
|  | @ -981,7 +982,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> { | |||
| impl Visitor<'_> { | ||||
|     pub(crate) fn process_hdl_let_pat( | ||||
|         &mut self, | ||||
|         _hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         mut let_stmt: Local, | ||||
|     ) -> Local { | ||||
|         let span = let_stmt.let_token.span(); | ||||
|  | @ -996,7 +997,6 @@ impl Visitor<'_> { | |||
|             init, | ||||
|             semi_token, | ||||
|         } = let_stmt; | ||||
|         self.require_normal_module_or_fn(let_token); | ||||
|         let Some(syn::LocalInit { | ||||
|             eq_token, | ||||
|             expr, | ||||
|  | @ -1031,20 +1031,38 @@ impl Visitor<'_> { | |||
|             errors: _, | ||||
|             bindings, | ||||
|         } = state; | ||||
|         let retval = parse_quote_spanned! {span=> | ||||
|         let ExprOptions { sim } = hdl_attr.body; | ||||
|         let retval = if sim.is_some() { | ||||
|             parse_quote_spanned! {span=> | ||||
|                 let (#(#bindings,)*) = { | ||||
|                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue; | ||||
|                     let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); | ||||
|                     #let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token | ||||
|                     (#(#bindings,)*) | ||||
|                 }; | ||||
|             } | ||||
|         } else { | ||||
|             parse_quote_spanned! {span=> | ||||
|                 let (#(#bindings,)* __scope,) = { | ||||
|                     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| { | ||||
|                     ::fayalite::expr::check_match_expr( | ||||
|                         __match_expr, | ||||
|                         |__match_value, __infallible| { | ||||
|                             #[allow(unused_variables)] | ||||
|                             #check_let_stmt | ||||
|                             match __infallible {} | ||||
|                 }); | ||||
|                         }, | ||||
|                     ); | ||||
|                     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 { | ||||
|                     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 { | ||||
|                     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) = | ||||
|  | @ -1054,6 +1072,7 @@ impl Visitor<'_> { | |||
|                     #let_token #pat #eq_token __match_variant #semi_token | ||||
|                     (#(#bindings,)* __scope,) | ||||
|                 }; | ||||
|             } | ||||
|         }; | ||||
|         match retval { | ||||
|             syn::Stmt::Local(retval) => retval, | ||||
|  | @ -1062,7 +1081,7 @@ impl Visitor<'_> { | |||
|     } | ||||
|     pub(crate) fn process_hdl_match( | ||||
|         &mut self, | ||||
|         _hdl_attr: HdlAttr<Nothing, kw::hdl>, | ||||
|         hdl_attr: HdlAttr<ExprOptions, kw::hdl>, | ||||
|         expr_match: ExprMatch, | ||||
|     ) -> Expr { | ||||
|         let span = expr_match.match_token.span(); | ||||
|  | @ -1074,7 +1093,6 @@ impl Visitor<'_> { | |||
|             brace_token: _, | ||||
|             arms, | ||||
|         } = expr_match; | ||||
|         self.require_normal_module_or_fn(match_token); | ||||
|         let mut state = HdlMatchParseState { | ||||
|             match_span: span, | ||||
|             errors: &mut self.errors, | ||||
|  | @ -1083,7 +1101,19 @@ impl Visitor<'_> { | |||
|             arms.into_iter() | ||||
|                 .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() { | ||||
|             quote_spanned! {span=> | ||||
|                 { | ||||
|                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue; | ||||
|                     let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); | ||||
|                     #match_token *__match_expr { | ||||
|                         #(#arms)* | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             quote_spanned! {span=> | ||||
|                 { | ||||
|                     type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; | ||||
|                     let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); | ||||
|  | @ -1101,6 +1131,7 @@ impl Visitor<'_> { | |||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|         syn::parse2(expr).unwrap() | ||||
|     } | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ use crate::{ | |||
|     }, | ||||
|     int::{Bool, DynSize}, | ||||
|     intern::{Intern, Interned}, | ||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue}, | ||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{ | ||||
|         impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, | ||||
|  | @ -562,29 +562,29 @@ macro_rules! impl_tuples { | |||
|                 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] | ||||
|             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical(ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty))) | ||||
|             fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical(ToSimValueWithType::<Bundle>::to_sim_value_with_type(self, Bundle::from_canonical(ty))) | ||||
|             } | ||||
|             #[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] | ||||
|             fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> { | ||||
|             fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { | ||||
|                 let ($($var,)*) = self; | ||||
|                 let [$($ty_var,)*] = *ty.fields() else { | ||||
|                     panic!("bundle has wrong number of fields"); | ||||
|                 }; | ||||
|                 $(let $var = $var.to_sim_value($ty_var.ty);)* | ||||
|                 ToSimValue::into_sim_value(($($var,)*), ty) | ||||
|                 $(let $var = $var.to_sim_value_with_type($ty_var.ty);)* | ||||
|                 ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty) | ||||
|             } | ||||
|             #[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(clippy::unused_unit)] | ||||
|                 let ($($var,)*) = self; | ||||
|  | @ -592,29 +592,44 @@ macro_rules! impl_tuples { | |||
|                     panic!("bundle has wrong number of fields"); | ||||
|                 }; | ||||
|                 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); | ||||
|                 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] | ||||
|             fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||
|             fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||
|                 let ($($var,)*) = self; | ||||
|                 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,)*)) | ||||
|             } | ||||
|             #[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 ($($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,)*)) | ||||
|             } | ||||
|         } | ||||
|         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,)*) { | ||||
|             fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> { | ||||
|                 let ($($lhs_var,)*) = *lhs; | ||||
|  | @ -674,7 +689,7 @@ impl_tuples! { | |||
| impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | ||||
|     type BaseType = Bundle; | ||||
|     type MaskType = (); | ||||
|     type SimValue = (); | ||||
|     type SimValue = PhantomData<T>; | ||||
|     type MatchVariant = PhantomData<T>; | ||||
|     type MatchActiveScope = (); | ||||
|     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 { | ||||
|         assert!(bits.is_empty()); | ||||
|         () | ||||
|         *self | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         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] | ||||
|     fn to_sim_value(&self, ty: Self) -> SimValue<Self> { | ||||
|         ToSimValue::into_sim_value(BitVec::new(), ty) | ||||
|     fn to_sim_value(&self) -> SimValue<Self> { | ||||
|         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] | ||||
|     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()); | ||||
|         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] | ||||
|     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); | ||||
|         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
 | ||||
| 
 | ||||
| use crate::{ | ||||
|     array::ArrayType, | ||||
|     expr::{ | ||||
|         target::{GetTarget, Target}, | ||||
|         Expr, NotALiteralExpr, ToExpr, ToLiteralBits, | ||||
|     }, | ||||
|     intern::{Intern, Interned, Memoize}, | ||||
|     sim::value::SimValue, | ||||
|     sim::value::{SimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, | ||||
|     util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, | ||||
|  | @ -58,7 +59,8 @@ pub trait KnownSize: | |||
|         + std::fmt::Debug | ||||
|         + IntoIterator<Item = SimValue<Element>> | ||||
|         + TryFrom<Vec<SimValue<Element>>> | ||||
|         + Into<Vec<SimValue<Element>>>; | ||||
|         + Into<Vec<SimValue<Element>>> | ||||
|         + ToSimValueWithType<ArrayType<Element, Self>>; | ||||
| } | ||||
| 
 | ||||
| macro_rules! known_widths { | ||||
|  | @ -120,7 +122,8 @@ pub trait Size: | |||
|         + std::fmt::Debug | ||||
|         + IntoIterator<Item = SimValue<Element>> | ||||
|         + TryFrom<Vec<SimValue<Element>>> | ||||
|         + Into<Vec<SimValue<Element>>>; | ||||
|         + Into<Vec<SimValue<Element>>> | ||||
|         + ToSimValueWithType<ArrayType<Element, Self>>; | ||||
|     const KNOWN_VALUE: Option<usize>; | ||||
|     type SizeType: SizeType<Size = Self> | ||||
|         + Copy | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ use crate::{ | |||
|     }, | ||||
|     int::Bool, | ||||
|     intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize}, | ||||
|     sim::value::{SimValue, SimValuePartialEq}, | ||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     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> { | ||||
|     type BaseType = PhantomConst; | ||||
|     type MaskType = (); | ||||
|     type SimValue = (); | ||||
|     type SimValue = PhantomConst<T>; | ||||
|     impl_match_variant_as_self!(); | ||||
| 
 | ||||
|     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 { | ||||
|         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_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_eq!(*value, *self); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -334,3 +336,23 @@ impl<T: ?Sized + PhantomConstValue> SimValuePartialEq<Self> for PhantomConst<T> | |||
|         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)?) | ||||
|         } | ||||
|         $(#[$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( | ||||
|                 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, | ||||
|             ); | ||||
|         } | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ use crate::{ | |||
|     expr::{CastBitsTo, Expr, ToExpr}, | ||||
|     int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, | ||||
|     reset::{AsyncReset, Reset, SyncReset}, | ||||
|     ty::{CanonicalType, Type}, | ||||
|     ty::{CanonicalType, StaticType, Type}, | ||||
|     util::{ | ||||
|         alternating_cell::{AlternatingCell, AlternatingCellMethods}, | ||||
|         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] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T>; | ||||
|     fn to_sim_value(&self) -> SimValue<Self::Type>; | ||||
|     #[track_caller] | ||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> | ||||
|     fn into_sim_value(self) -> SimValue<Self::Type> | ||||
|     where | ||||
|         Self: Sized, | ||||
|     { | ||||
|         self.to_sim_value(ty) | ||||
|         self.to_sim_value() | ||||
|     } | ||||
|     #[track_caller] | ||||
|     fn arc_into_sim_value(self: Arc<Self>, ty: T) -> SimValue<T> { | ||||
|         self.to_sim_value(ty) | ||||
|     fn arc_into_sim_value(self: Arc<Self>) -> SimValue<Self::Type> { | ||||
|         self.to_sim_value() | ||||
|     } | ||||
|     #[track_caller] | ||||
|     fn arc_to_sim_value(self: &Arc<Self>, ty: T) -> SimValue<T> { | ||||
|         self.to_sim_value(ty) | ||||
|     fn arc_to_sim_value(self: &Arc<Self>) -> SimValue<Self::Type> { | ||||
|         self.to_sim_value() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> ToSimValue<T> for SimValue<T> { | ||||
| pub trait ToSimValueWithType<T: Type> { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         assert_eq!(SimValue::ty(self), ty); | ||||
|     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T>; | ||||
|     #[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() | ||||
|     } | ||||
| 
 | ||||
|     #[track_caller] | ||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { | ||||
|         assert_eq!(SimValue::ty(&self), ty); | ||||
|     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||
|         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] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         self.clone().into_sim_value(ty) | ||||
|     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||
|         self.clone().into_sim_value_with_type(ty) | ||||
|     } | ||||
| 
 | ||||
|     #[track_caller] | ||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { | ||||
|         Arc::new(self).arc_into_sim_value(ty) | ||||
|     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||
|         Arc::new(self).arc_into_sim_value_with_type(ty) | ||||
|     } | ||||
| 
 | ||||
|     #[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)) | ||||
|     } | ||||
| 
 | ||||
|     #[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())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Type> ToSimValue<T> for bitvec::boxed::BitBox { | ||||
| impl<T: Type> ToSimValueWithType<T> for bitvec::boxed::BitBox { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         self.clone().into_sim_value(ty) | ||||
|     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||
|         self.clone().into_sim_value_with_type(ty) | ||||
|     } | ||||
| 
 | ||||
|     #[track_caller] | ||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { | ||||
|         self.into_bitvec().into_sim_value(ty) | ||||
|     fn into_sim_value_with_type(self, ty: T) -> SimValue<T> { | ||||
|         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] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         self.to_bitvec().into_sim_value(ty) | ||||
|     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||
|         self.to_bitvec().into_sim_value_with_type(ty) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for &'_ This { | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         This::to_sim_value(self, ty) | ||||
| impl<This: ?Sized + ToSimValue> ToSimValue for &'_ This { | ||||
|     type Type = This::Type; | ||||
| 
 | ||||
|     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 { | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         This::to_sim_value(self, ty) | ||||
| impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for &'_ This { | ||||
|     fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> { | ||||
|         This::to_sim_value_with_type(self, ty) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for Arc<This> { | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         This::arc_to_sim_value(self, ty) | ||||
|     } | ||||
|     fn into_sim_value(self, ty: T) -> SimValue<T> { | ||||
|         This::arc_into_sim_value(self, ty) | ||||
| impl<This: ?Sized + ToSimValue> ToSimValue for &'_ mut This { | ||||
|     type Type = This::Type; | ||||
| 
 | ||||
|     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||
|         This::to_sim_value(self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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> | ||||
| { | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         This::to_sim_value(self, ty) | ||||
|     type Type = This::Type; | ||||
|     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||
|         This::to_sim_value(self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<This: ToSimValue<T>, T: Type> ToSimValue<T> for Box<This> { | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         This::to_sim_value(self, ty) | ||||
| impl<This: ?Sized + ToSimValueWithType<T> + Send + Sync + 'static, T: Type> ToSimValueWithType<T> | ||||
|     for crate::intern::Interned<This> | ||||
| { | ||||
|     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>> { | ||||
|     #[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>, | ||||
|         elements: I, | ||||
|     ) -> Self { | ||||
|  | @ -430,23 +531,32 @@ impl<T: Type, Len: Size> SimValue<ArrayType<T, Len>> { | |||
|         let elements = Vec::from_iter( | ||||
|             elements | ||||
|                 .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()); | ||||
|         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] | ||||
|     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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for [Element] { | ||||
| impl<Element: ToSimValue<Type: StaticType>> ToSimValue for [Element] { | ||||
|     type Type = Array<Element::Type>; | ||||
| 
 | ||||
|     #[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( | ||||
|             <Array>::from_canonical(ty), | ||||
|             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 | ||||
|     ConstUsize<N>: KnownSize, | ||||
| { | ||||
|     #[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) | ||||
|     } | ||||
|     #[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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<Element: ToSimValue<T>, T: Type, const N: usize> ToSimValue<Array<T>> for [Element; N] { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> { | ||||
|         SimValue::from_array_elements(ty, self) | ||||
| impl<Element: ToSimValue<Type: StaticType>, const N: usize> ToSimValue for [Element; N] | ||||
| where | ||||
|     ConstUsize<N>: KnownSize, | ||||
| { | ||||
|     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>> { | ||||
|         SimValue::from_array_elements(ty, self) | ||||
| 
 | ||||
|     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||
|         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] | ||||
| { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|         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>> { | ||||
|     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(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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for Vec<Element> { | ||||
| impl<Element: ToSimValueWithType<CanonicalType>, const N: usize> ToSimValueWithType<CanonicalType> | ||||
|     for [Element; N] | ||||
| { | ||||
|     #[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( | ||||
|             <Array>::from_canonical(ty), | ||||
|             self, | ||||
|         )) | ||||
|     } | ||||
|     #[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( | ||||
|             <Array>::from_canonical(ty), | ||||
|             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] | ||||
|     fn to_sim_value(&self, ty: T) -> SimValue<T> { | ||||
|         assert_eq!(Expr::ty(*self), ty); | ||||
|     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 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( | ||||
|             ty, | ||||
|             Expr::ty(*self), | ||||
|             &crate::expr::ToLiteralBits::to_literal_bits(self) | ||||
|                 .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 { | ||||
|     ($ty:ident) => { | ||||
|         impl ToSimValue<$ty> for bool { | ||||
|             fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> { | ||||
|         impl ToSimValueWithType<$ty> for bool { | ||||
|             fn to_sim_value_with_type(&self, ty: $ty) -> SimValue<$ty> { | ||||
|                 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!(AsyncReset); | ||||
| impl_to_sim_value_for_bool_like!(SyncReset); | ||||
| impl_to_sim_value_for_bool_like!(Reset); | ||||
| impl_to_sim_value_for_bool_like!(Clock); | ||||
| 
 | ||||
| impl ToSimValue<CanonicalType> for bool { | ||||
| impl ToSimValueWithType<CanonicalType> for bool { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|         match ty { | ||||
|             CanonicalType::UInt(_) | ||||
|             | CanonicalType::SInt(_) | ||||
|  | @ -579,19 +773,22 @@ impl ToSimValue<CanonicalType> for bool { | |||
| 
 | ||||
| macro_rules! impl_to_sim_value_for_primitive_int { | ||||
|     ($prim:ident) => { | ||||
|         impl ToSimValue<<$prim as ToExpr>::Type> for $prim { | ||||
|         impl ToSimValue for $prim { | ||||
|             type Type = <$prim as ToExpr>::Type; | ||||
| 
 | ||||
|             #[track_caller] | ||||
|             fn to_sim_value( | ||||
|                 &self, | ||||
|                 ty: <$prim as ToExpr>::Type, | ||||
|             ) -> SimValue<<$prim as ToExpr>::Type> { | ||||
|                 SimValue::from_value(ty, (*self).into()) | ||||
|             ) -> SimValue<Self::Type> { | ||||
|                 SimValue::from_value(StaticType::TYPE, (*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] | ||||
|             fn to_sim_value( | ||||
|             fn to_sim_value_with_type( | ||||
|                 &self, | ||||
|                 ty: <<$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] | ||||
|             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); | ||||
|                 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 { | ||||
|     ($IntValue:ident, $Int:ident, $IntType:ident) => { | ||||
|         impl<Width: KnownSize> ToSimValue<$IntType<Width>> for $IntValue<Width> { | ||||
|             fn to_sim_value(&self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { | ||||
|                 self.bits().to_sim_value(ty) | ||||
|         impl<Width: Size> ToSimValue for $IntValue<Width> { | ||||
|             type Type = $IntType<Width>; | ||||
| 
 | ||||
|             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>> { | ||||
|                 self.into_bits().into_sim_value(ty) | ||||
|             fn into_sim_value(self) -> SimValue<Self::Type> { | ||||
|                 SimValue::from_value(self.ty(), self) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl<Width: Size> ToSimValue<$Int> for $IntValue<Width> { | ||||
|             fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> { | ||||
|                 self.bits().to_sim_value(ty) | ||||
|         impl<Width: Size> ToSimValueWithType<$IntType<Width>> for $IntValue<Width> { | ||||
|             fn to_sim_value_with_type(&self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { | ||||
|                 SimValue::from_value(ty, self.clone()) | ||||
|             } | ||||
| 
 | ||||
|             fn into_sim_value(self, ty: $Int) -> SimValue<$Int> { | ||||
|                 self.into_bits().into_sim_value(ty) | ||||
|             fn into_sim_value_with_type(self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> { | ||||
|                 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] | ||||
|             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical(self.to_sim_value($Int::from_canonical(ty))) | ||||
|             fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical( | ||||
|                     self.to_sim_value_with_type($IntType::<Width>::from_canonical(ty)), | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
|             #[track_caller] | ||||
|             fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical(self.into_sim_value($Int::from_canonical(ty))) | ||||
|             fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|                 SimValue::into_canonical( | ||||
|                     self.into_sim_value_with_type($IntType::<Width>::from_canonical(ty)), | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ use crate::{ | |||
|     intern::{Intern, Interned}, | ||||
|     phantom_const::PhantomConst, | ||||
|     reset::{AsyncReset, Reset, SyncReset}, | ||||
|     sim::value::{SimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     util::ConstUsize, | ||||
| }; | ||||
|  | @ -269,7 +270,7 @@ pub trait Type: | |||
| { | ||||
|     type BaseType: BaseType; | ||||
|     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 MatchActiveScope; | ||||
|     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 { | ||||
|     const TYPE: Self; | ||||
|     const MASK_TYPE: Self::MaskType; | ||||
|  |  | |||
|  | @ -7,13 +7,7 @@ use fayalite::{ | |||
|     module::{instance_with_loc, reg_builder_with_loc}, | ||||
|     prelude::*, | ||||
|     reset::ResetType, | ||||
|     sim::{ | ||||
|         time::SimDuration, | ||||
|         value::{SimValue, ToSimValue}, | ||||
|         vcd::VcdWriterDecls, | ||||
|         Simulation, | ||||
|     }, | ||||
|     ty::StaticType, | ||||
|     sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation}, | ||||
|     util::RcWriter, | ||||
| }; | ||||
| use std::num::NonZeroUsize; | ||||
|  | @ -391,113 +385,110 @@ fn test_enums() { | |||
|     let mut sim = Simulation::new(enums()); | ||||
|     let mut writer = RcWriter::default(); | ||||
|     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); | ||||
|     sim.write_clock(sim.io().cd.clk, false); | ||||
|     sim.write_reset(sim.io().cd.rst, true); | ||||
|     sim.write_bool(sim.io().en, false); | ||||
|     sim.write_bool_or_int(sim.io().which_in, 0_hdl_u2); | ||||
|     sim.write_bool_or_int(sim.io().data_in, 0_hdl_u4); | ||||
|     sim.write(sim.io().cd.clk, false); | ||||
|     sim.write(sim.io().cd.rst, true); | ||||
|     sim.write(sim.io().en, false); | ||||
|     sim.write(sim.io().which_in, 0_hdl_u2); | ||||
|     sim.write(sim.io().data_in, 0_hdl_u4); | ||||
|     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.write_reset(sim.io().cd.rst, false); | ||||
|     sim.write(sim.io().cd.rst, false); | ||||
|     sim.advance_time(SimDuration::from_nanos(900)); | ||||
|     type BOutTy = HdlOption<(UInt<1>, Bool)>; | ||||
|     #[derive(Debug, PartialEq)] | ||||
|     #[hdl(cmp_eq)] | ||||
|     struct IO { | ||||
|         en: bool, | ||||
|         which_in: u8, | ||||
|         data_in: u8, | ||||
|         which_out: u8, | ||||
|         data_out: u8, | ||||
|         b_out: SimValue<BOutTy>, | ||||
|         en: Bool, | ||||
|         which_in: UInt<2>, | ||||
|         data_in: UInt<4>, | ||||
|         which_out: UInt<2>, | ||||
|         data_out: UInt<4>, | ||||
|         b_out: HdlOption<(UInt<1>, Bool)>, | ||||
|     } | ||||
|     let io_cycles = [ | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: false, | ||||
|             which_in: 0, | ||||
|             data_in: 0, | ||||
|             which_out: 0, | ||||
|             data_out: 0, | ||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), | ||||
|             which_in: 0_hdl_u2, | ||||
|             data_in: 0_hdl_u4, | ||||
|             which_out: 0_hdl_u2, | ||||
|             data_out: 0_hdl_u4, | ||||
|             b_out: HdlNone(), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: true, | ||||
|             which_in: 1, | ||||
|             data_in: 0, | ||||
|             which_out: 0, | ||||
|             data_out: 0, | ||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), | ||||
|             which_in: 1_hdl_u2, | ||||
|             data_in: 0_hdl_u4, | ||||
|             which_out: 0_hdl_u2, | ||||
|             data_out: 0_hdl_u4, | ||||
|             b_out: HdlNone(), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: false, | ||||
|             which_in: 0, | ||||
|             data_in: 0, | ||||
|             which_out: 1, | ||||
|             data_out: 0, | ||||
|             b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), | ||||
|             which_in: 0_hdl_u2, | ||||
|             data_in: 0_hdl_u4, | ||||
|             which_out: 1_hdl_u2, | ||||
|             data_out: 0_hdl_u4, | ||||
|             b_out: HdlSome((0_hdl_u1, false)), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: true, | ||||
|             which_in: 1, | ||||
|             data_in: 0xF, | ||||
|             which_out: 1, | ||||
|             data_out: 0, | ||||
|             b_out: HdlSome((0_hdl_u1, false)).to_sim_value(StaticType::TYPE), | ||||
|             which_in: 1_hdl_u2, | ||||
|             data_in: 0xF_hdl_u4, | ||||
|             which_out: 1_hdl_u2, | ||||
|             data_out: 0_hdl_u4, | ||||
|             b_out: HdlSome((0_hdl_u1, false)), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: true, | ||||
|             which_in: 1, | ||||
|             data_in: 0xF, | ||||
|             which_out: 1, | ||||
|             data_out: 0x3, | ||||
|             b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), | ||||
|             which_in: 1_hdl_u2, | ||||
|             data_in: 0xF_hdl_u4, | ||||
|             which_out: 1_hdl_u2, | ||||
|             data_out: 0x3_hdl_u4, | ||||
|             b_out: HdlSome((1_hdl_u1, true)), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: true, | ||||
|             which_in: 2, | ||||
|             data_in: 0xF, | ||||
|             which_out: 1, | ||||
|             data_out: 0x3, | ||||
|             b_out: HdlSome((1_hdl_u1, true)).to_sim_value(StaticType::TYPE), | ||||
|             which_in: 2_hdl_u2, | ||||
|             data_in: 0xF_hdl_u4, | ||||
|             which_out: 1_hdl_u2, | ||||
|             data_out: 0x3_hdl_u4, | ||||
|             b_out: HdlSome((1_hdl_u1, true)), | ||||
|         }, | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             en: true, | ||||
|             which_in: 2, | ||||
|             data_in: 0xF, | ||||
|             which_out: 2, | ||||
|             data_out: 0xF, | ||||
|             b_out: HdlNone().to_sim_value(StaticType::TYPE), | ||||
|             which_in: 2_hdl_u2, | ||||
|             data_in: 0xF_hdl_u4, | ||||
|             which_out: 2_hdl_u2, | ||||
|             data_out: 0xF_hdl_u4, | ||||
|             b_out: HdlNone(), | ||||
|         }, | ||||
|     ]; | ||||
|     for ( | ||||
|         cycle, | ||||
|         expected @ IO { | ||||
|     for (cycle, expected) in io_cycles.into_iter().enumerate() { | ||||
|         #[hdl(sim)] | ||||
|         let IO { | ||||
|             en, | ||||
|             which_in, | ||||
|             data_in, | ||||
|             which_out: _, | ||||
|             data_out: _, | ||||
|             b_out: _, | ||||
|         }, | ||||
|     ) in io_cycles.into_iter().enumerate() | ||||
|     { | ||||
|         sim.write_bool(sim.io().en, en); | ||||
|         sim.write_bool_or_int(sim.io().which_in, which_in.cast_to_static()); | ||||
|         sim.write_bool_or_int(sim.io().data_in, data_in.cast_to_static()); | ||||
|         let io = IO { | ||||
|         } = expected; | ||||
|         sim.write(sim.io().en, &en); | ||||
|         sim.write(sim.io().which_in, &which_in); | ||||
|         sim.write(sim.io().data_in, &data_in); | ||||
|         let io = #[hdl(sim)] | ||||
|         IO { | ||||
|             en, | ||||
|             which_in, | ||||
|             data_in, | ||||
|             which_out: sim | ||||
|                 .read_bool_or_int(sim.io().which_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"), | ||||
|             which_out: sim.read(sim.io().which_out), | ||||
|             data_out: sim.read(sim.io().data_out), | ||||
|             b_out: sim.read(sim.io().b_out), | ||||
|         }; | ||||
|         assert_eq!( | ||||
|  | @ -559,7 +550,7 @@ fn test_memories() { | |||
|         w_mask: (Bool, Bool), | ||||
|     } | ||||
|     let io_cycles = [ | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: false, | ||||
|  | @ -569,7 +560,7 @@ fn test_memories() { | |||
|             w_data: (0u8, 0i8), | ||||
|             w_mask: (false, false), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -579,7 +570,7 @@ fn test_memories() { | |||
|             w_data: (0x10u8, 0x20i8), | ||||
|             w_mask: (true, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -589,7 +580,7 @@ fn test_memories() { | |||
|             w_data: (0x30u8, 0x40i8), | ||||
|             w_mask: (false, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -599,7 +590,7 @@ fn test_memories() { | |||
|             w_data: (0x50u8, 0x60i8), | ||||
|             w_mask: (true, false), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -609,7 +600,7 @@ fn test_memories() { | |||
|             w_data: (0x70u8, -0x80i8), | ||||
|             w_mask: (false, false), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -619,7 +610,7 @@ fn test_memories() { | |||
|             w_data: (0x90u8, 0xA0u8 as i8), | ||||
|             w_mask: (false, false), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -629,7 +620,7 @@ fn test_memories() { | |||
|             w_data: (0x90u8, 0xA0u8 as i8), | ||||
|             w_mask: (true, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -639,7 +630,7 @@ fn test_memories() { | |||
|             w_data: (0xB0u8, 0xC0u8 as i8), | ||||
|             w_mask: (true, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 0_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -649,7 +640,7 @@ fn test_memories() { | |||
|             w_data: (0xD0u8, 0xE0u8 as i8), | ||||
|             w_mask: (true, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 1_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -659,7 +650,7 @@ fn test_memories() { | |||
|             w_data: (0xD0u8, 0xE0u8 as i8), | ||||
|             w_mask: (true, true), | ||||
|         }, | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr: 2_hdl_u4, | ||||
|             r_en: true, | ||||
|  | @ -671,7 +662,7 @@ fn test_memories() { | |||
|         }, | ||||
|     ]; | ||||
|     for (cycle, expected) in io_cycles.into_iter().enumerate() { | ||||
|         #[hdl] | ||||
|         #[hdl(sim)] | ||||
|         let IO { | ||||
|             r_addr, | ||||
|             r_en, | ||||
|  | @ -681,13 +672,13 @@ fn test_memories() { | |||
|             w_data, | ||||
|             w_mask, | ||||
|         } = expected; | ||||
|         sim.write(sim.io().r.addr, r_addr); | ||||
|         sim.write(sim.io().r.en, r_en); | ||||
|         sim.write(sim.io().w.addr, w_addr); | ||||
|         sim.write(sim.io().w.en, w_en); | ||||
|         sim.write(sim.io().w.data, w_data); | ||||
|         sim.write(sim.io().w.mask, w_mask); | ||||
|         let io = (#[hdl] | ||||
|         sim.write(sim.io().r.addr, &r_addr); | ||||
|         sim.write(sim.io().r.en, &r_en); | ||||
|         sim.write(sim.io().w.addr, &w_addr); | ||||
|         sim.write(sim.io().w.en, &w_en); | ||||
|         sim.write(sim.io().w.data, &w_data); | ||||
|         sim.write(sim.io().w.mask, &w_mask); | ||||
|         let io = #[hdl(sim)] | ||||
|         IO { | ||||
|             r_addr, | ||||
|             r_en, | ||||
|  | @ -696,20 +687,19 @@ fn test_memories() { | |||
|             w_en, | ||||
|             w_data, | ||||
|             w_mask, | ||||
|         }) | ||||
|         .to_sim_value(StaticType::TYPE); | ||||
|         }; | ||||
|         assert_eq!( | ||||
|             expected.to_sim_value(StaticType::TYPE), | ||||
|             expected, | ||||
|             io, | ||||
|             "vcd:\n{}\ncycle: {cycle}", | ||||
|             String::from_utf8(writer.take()).unwrap(), | ||||
|         ); | ||||
|         sim.advance_time(SimDuration::from_micros(1)); | ||||
|         sim.write_clock(sim.io().r.clk, true); | ||||
|         sim.write_clock(sim.io().w.clk, true); | ||||
|         sim.write(sim.io().r.clk, true); | ||||
|         sim.write(sim.io().w.clk, true); | ||||
|         sim.advance_time(SimDuration::from_micros(1)); | ||||
|         sim.write_clock(sim.io().r.clk, false); | ||||
|         sim.write_clock(sim.io().w.clk, false); | ||||
|         sim.write(sim.io().r.clk, false); | ||||
|         sim.write(sim.io().w.clk, false); | ||||
|     } | ||||
|     sim.flush_traces().unwrap(); | ||||
|     let vcd = String::from_utf8(writer.take()).unwrap(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue