forked from libre-chip/fayalite
		
	WIP making progress
This commit is contained in:
		
							parent
							
								
									6d36698adf
								
							
						
					
					
						commit
						9b12ff54e6
					
				
					 22 changed files with 2326 additions and 613 deletions
				
			
		|  | @ -674,23 +674,24 @@ impl ToTokens for ParsedBundle { | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|         )); |         )); | ||||||
|         let sim_value_from_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { |         let sim_value_from_opaque_fields = | ||||||
|             let ident: &Ident = field.ident().as_ref().unwrap(); |  | ||||||
|             quote_spanned! {span=> |  | ||||||
|                 #ident: v.field_from_bits(), |  | ||||||
|             } |  | ||||||
|         })); |  | ||||||
|         let sim_value_clone_from_bits_fields = |  | ||||||
|             Vec::from_iter(fields.named().into_iter().map(|field| { |             Vec::from_iter(fields.named().into_iter().map(|field| { | ||||||
|                 let ident: &Ident = field.ident().as_ref().unwrap(); |                 let ident: &Ident = field.ident().as_ref().unwrap(); | ||||||
|                 quote_spanned! {span=> |                 quote_spanned! {span=> | ||||||
|                     v.field_clone_from_bits(&mut value.#ident); |                     #ident: v.field_from_opaque(), | ||||||
|                 } |                 } | ||||||
|             })); |             })); | ||||||
|         let sim_value_to_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { |         let sim_value_clone_from_opaque_fields = | ||||||
|  |             Vec::from_iter(fields.named().into_iter().map(|field| { | ||||||
|  |                 let ident: &Ident = field.ident().as_ref().unwrap(); | ||||||
|  |                 quote_spanned! {span=> | ||||||
|  |                     v.field_clone_from_opaque(&mut value.#ident); | ||||||
|  |                 } | ||||||
|  |             })); | ||||||
|  |         let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| { | ||||||
|             let ident: &Ident = field.ident().as_ref().unwrap(); |             let ident: &Ident = field.ident().as_ref().unwrap(); | ||||||
|             quote_spanned! {span=> |             quote_spanned! {span=> | ||||||
|                 v.field_to_bits(&value.#ident); |                 v.field(&value.#ident); | ||||||
|             } |             } | ||||||
|         })); |         })); | ||||||
|         let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { |         let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { | ||||||
|  | @ -745,33 +746,34 @@ impl ToTokens for ParsedBundle { | ||||||
|                 fn source_location() -> ::fayalite::source_location::SourceLocation { |                 fn source_location() -> ::fayalite::source_location::SourceLocation { | ||||||
|                     ::fayalite::source_location::SourceLocation::caller() |                     ::fayalite::source_location::SourceLocation::caller() | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_from_bits( |                 fn sim_value_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) -> <Self as ::fayalite::ty::Type>::SimValue { |                 ) -> <Self as ::fayalite::ty::Type>::SimValue { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                     #mask_type_sim_value_ident { |                     #mask_type_sim_value_ident { | ||||||
|                         #(#sim_value_from_bits_fields)* |                         #(#sim_value_from_opaque_fields)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_clone_from_bits( |                 fn sim_value_clone_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, |                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) { |                 ) { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                     #(#sim_value_clone_from_bits_fields)* |                     #(#sim_value_clone_from_opaque_fields)* | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_to_bits( |                 fn sim_value_to_opaque<'__w>( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &<Self as ::fayalite::ty::Type>::SimValue, |                     value: &<Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &mut ::fayalite::bitvec::slice::BitSlice, |                     writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, | ||||||
|                 ) { |                 ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); | ||||||
|                     #(#sim_value_to_bits_fields)* |                     #(#sim_value_to_opaque_fields)* | ||||||
|  |                     v.finish() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             #[automatically_derived] |             #[automatically_derived] | ||||||
|  | @ -894,33 +896,34 @@ impl ToTokens for ParsedBundle { | ||||||
|                 fn source_location() -> ::fayalite::source_location::SourceLocation { |                 fn source_location() -> ::fayalite::source_location::SourceLocation { | ||||||
|                     ::fayalite::source_location::SourceLocation::caller() |                     ::fayalite::source_location::SourceLocation::caller() | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_from_bits( |                 fn sim_value_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) -> <Self as ::fayalite::ty::Type>::SimValue { |                 ) -> <Self as ::fayalite::ty::Type>::SimValue { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                     #sim_value_ident { |                     #sim_value_ident { | ||||||
|                         #(#sim_value_from_bits_fields)* |                         #(#sim_value_from_opaque_fields)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_clone_from_bits( |                 fn sim_value_clone_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, |                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) { |                 ) { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                     #(#sim_value_clone_from_bits_fields)* |                     #(#sim_value_clone_from_opaque_fields)* | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_to_bits( |                 fn sim_value_to_opaque<'__w>( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &<Self as ::fayalite::ty::Type>::SimValue, |                     value: &<Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &mut ::fayalite::bitvec::slice::BitSlice, |                     writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, | ||||||
|                 ) { |                 ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { | ||||||
|                     #![allow(unused_mut, unused_variables)] |                     #![allow(unused_mut, unused_variables)] | ||||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); |                     let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); | ||||||
|                     #(#sim_value_to_bits_fields)* |                     #(#sim_value_to_opaque_fields)* | ||||||
|  |                     v.finish() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             #[automatically_derived] |             #[automatically_derived] | ||||||
|  |  | ||||||
|  | @ -701,18 +701,18 @@ impl ToTokens for ParsedEnum { | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|         )); |         )); | ||||||
|         let sim_value_from_bits_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = |         let sim_value_from_opaque_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = | ||||||
|             &sim_value_unknown_variant_name |             &sim_value_unknown_variant_name | ||||||
|         { |         { | ||||||
|             quote_spanned! {span=> |             quote_spanned! {span=> | ||||||
|                 _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_bits()), |                 _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_opaque()), | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             quote_spanned! {span=> |             quote_spanned! {span=> | ||||||
|                 _ => ::fayalite::__std::unreachable!(), |                 _ => ::fayalite::__std::unreachable!(), | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         let sim_value_from_bits_match_arms = Vec::from_iter( |         let sim_value_from_opaque_match_arms = Vec::from_iter( | ||||||
|             variants |             variants | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|  | @ -729,29 +729,29 @@ impl ToTokens for ParsedEnum { | ||||||
|                         if let Some(_) = field { |                         if let Some(_) = field { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #index => { |                                 #index => { | ||||||
|                                     let (field, padding) = v.variant_with_field_from_bits(); |                                     let (field, padding) = v.variant_with_field_from_opaque(); | ||||||
|                                     #sim_value_ident::#ident(field, padding) |                                     #sim_value_ident::#ident(field, padding) | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #index => #sim_value_ident::#ident( |                                 #index => #sim_value_ident::#ident( | ||||||
|                                     v.variant_no_field_from_bits(), |                                     v.variant_no_field_from_opaque(), | ||||||
|                                 ), |                                 ), | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                 ) |                 ) | ||||||
|                 .chain([sim_value_from_bits_unknown_match_arm]), |                 .chain([sim_value_from_opaque_unknown_match_arm]), | ||||||
|         ); |         ); | ||||||
|         let sim_value_clone_from_bits_unknown_match_arm = |         let sim_value_clone_from_opaque_unknown_match_arm = | ||||||
|             if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { |             if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { | ||||||
|                 quote_spanned! {span=> |                 quote_spanned! {span=> | ||||||
|                     _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { |                     _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { | ||||||
|                         v.unknown_variant_clone_from_bits(value); |                         v.unknown_variant_clone_from_opaque(value); | ||||||
|                     } else { |                     } else { | ||||||
|                         *value = #sim_value_ident::#sim_value_unknown_variant_name( |                         *value = #sim_value_ident::#sim_value_unknown_variant_name( | ||||||
|                             v.unknown_variant_from_bits(), |                             v.unknown_variant_from_opaque(), | ||||||
|                         ); |                         ); | ||||||
|                     }, |                     }, | ||||||
|                 } |                 } | ||||||
|  | @ -760,7 +760,7 @@ impl ToTokens for ParsedEnum { | ||||||
|                     _ => ::fayalite::__std::unreachable!(), |                     _ => ::fayalite::__std::unreachable!(), | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|         let sim_value_clone_from_bits_match_arms = Vec::from_iter( |         let sim_value_clone_from_opaque_match_arms = Vec::from_iter( | ||||||
|             variants |             variants | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|  | @ -777,28 +777,28 @@ impl ToTokens for ParsedEnum { | ||||||
|                         if let Some(_) = field { |                         if let Some(_) = field { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #index => if let #sim_value_ident::#ident(field, padding) = value { |                                 #index => if let #sim_value_ident::#ident(field, padding) = value { | ||||||
|                                     v.variant_with_field_clone_from_bits(field, padding); |                                     v.variant_with_field_clone_from_opaque(field, padding); | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     let (field, padding) = v.variant_with_field_from_bits(); |                                     let (field, padding) = v.variant_with_field_from_opaque(); | ||||||
|                                     *value = #sim_value_ident::#ident(field, padding); |                                     *value = #sim_value_ident::#ident(field, padding); | ||||||
|                                 }, |                                 }, | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #index => if let #sim_value_ident::#ident(padding) = value { |                                 #index => if let #sim_value_ident::#ident(padding) = value { | ||||||
|                                     v.variant_no_field_clone_from_bits(padding); |                                     v.variant_no_field_clone_from_opaque(padding); | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     *value = #sim_value_ident::#ident( |                                     *value = #sim_value_ident::#ident( | ||||||
|                                         v.variant_no_field_from_bits(), |                                         v.variant_no_field_from_opaque(), | ||||||
|                                     ); |                                     ); | ||||||
|                                 }, |                                 }, | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                 ) |                 ) | ||||||
|                 .chain([sim_value_clone_from_bits_unknown_match_arm]), |                 .chain([sim_value_clone_from_opaque_unknown_match_arm]), | ||||||
|         ); |         ); | ||||||
|         let sim_value_to_bits_match_arms = Vec::from_iter( |         let sim_value_to_opaque_match_arms = Vec::from_iter( | ||||||
|             variants |             variants | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|  | @ -815,13 +815,13 @@ impl ToTokens for ParsedEnum { | ||||||
|                         if let Some(_) = field { |                         if let Some(_) = field { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #sim_value_ident::#ident(field, padding) => { |                                 #sim_value_ident::#ident(field, padding) => { | ||||||
|                                     v.variant_with_field_to_bits(#index, field, padding); |                                     v.variant_with_field_to_opaque(#index, field, padding) | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
|                             quote_spanned! {span=> |                             quote_spanned! {span=> | ||||||
|                                 #sim_value_ident::#ident(padding) => { |                                 #sim_value_ident::#ident(padding) => { | ||||||
|                                     v.variant_no_field_to_bits(#index, padding); |                                     v.variant_no_field_to_opaque(#index, padding) | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|  | @ -831,7 +831,7 @@ impl ToTokens for ParsedEnum { | ||||||
|                     |sim_value_unknown_variant_name| { |                     |sim_value_unknown_variant_name| { | ||||||
|                         quote_spanned! {span=> |                         quote_spanned! {span=> | ||||||
|                             #sim_value_ident::#sim_value_unknown_variant_name(value) => { |                             #sim_value_ident::#sim_value_unknown_variant_name(value) => { | ||||||
|                                 v.unknown_variant_to_bits(value); |                                 v.unknown_variant_to_opaque(value) | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|  | @ -878,33 +878,33 @@ impl ToTokens for ParsedEnum { | ||||||
|                 fn source_location() -> ::fayalite::source_location::SourceLocation { |                 fn source_location() -> ::fayalite::source_location::SourceLocation { | ||||||
|                     ::fayalite::source_location::SourceLocation::caller() |                     ::fayalite::source_location::SourceLocation::caller() | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_from_bits( |                 fn sim_value_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) -> <Self as ::fayalite::ty::Type>::SimValue { |                 ) -> <Self as ::fayalite::ty::Type>::SimValue { | ||||||
|                     let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); |                     let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque); | ||||||
|                     match v.discriminant() { |                     match v.discriminant() { | ||||||
|                         #(#sim_value_from_bits_match_arms)* |                         #(#sim_value_from_opaque_match_arms)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_clone_from_bits( |                 fn sim_value_clone_from_opaque( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, |                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, |                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||||
|                 ) { |                 ) { | ||||||
|                     let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); |                     let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque); | ||||||
|                     match v.discriminant() { |                     match v.discriminant() { | ||||||
|                         #(#sim_value_clone_from_bits_match_arms)* |                         #(#sim_value_clone_from_opaque_match_arms)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 fn sim_value_to_bits( |                 fn sim_value_to_opaque<'__w>( | ||||||
|                     &self, |                     &self, | ||||||
|                     value: &<Self as ::fayalite::ty::Type>::SimValue, |                     value: &<Self as ::fayalite::ty::Type>::SimValue, | ||||||
|                     bits: &mut ::fayalite::bitvec::slice::BitSlice, |                     writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, | ||||||
|                 ) { |                 ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { | ||||||
|                     let v = ::fayalite::enum_::EnumSimValueToBits::new(*self, bits); |                     let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer); | ||||||
|                     match value { |                     match value { | ||||||
|                         #(#sim_value_to_bits_match_arms)* |                         #(#sim_value_to_opaque_match_arms)* | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -12,12 +12,12 @@ use crate::{ | ||||||
|     sim::value::{SimValue, SimValuePartialEq}, |     sim::value::{SimValue, SimValuePartialEq}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, |         CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter, | ||||||
|  |         OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref, | ||||||
|         serde_impls::SerdeCanonicalType, |         serde_impls::SerdeCanonicalType, | ||||||
|     }, |     }, | ||||||
|     util::ConstUsize, |     util::ConstUsize, | ||||||
| }; | }; | ||||||
| use bitvec::slice::BitSlice; |  | ||||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; | use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; | ||||||
| use std::{iter::FusedIterator, ops::Index}; | use std::{iter::FusedIterator, ops::Index}; | ||||||
| 
 | 
 | ||||||
|  | @ -48,15 +48,20 @@ impl<T: Type, Len: Size> ArrayType<T, Len> { | ||||||
|             is_storable, |             is_storable, | ||||||
|             is_castable_from_bits, |             is_castable_from_bits, | ||||||
|             bit_width, |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|         } = element; |         } = element; | ||||||
|         let Some(bit_width) = bit_width.checked_mul(len) else { |         let Some(bit_width) = bit_width.checked_mul(len) else { | ||||||
|             panic!("array too big"); |             panic!("array too big"); | ||||||
|         }; |         }; | ||||||
|  |         let Some(sim_only_values_len) = sim_only_values_len.checked_mul(len) else { | ||||||
|  |             panic!("array too big"); | ||||||
|  |         }; | ||||||
|         TypeProperties { |         TypeProperties { | ||||||
|             is_passive, |             is_passive, | ||||||
|             is_storable, |             is_storable, | ||||||
|             is_castable_from_bits, |             is_castable_from_bits, | ||||||
|             bit_width, |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     pub fn new(element: T, len: Len::SizeType) -> Self { |     pub fn new(element: T, len: Len::SizeType) -> Self { | ||||||
|  | @ -194,42 +199,51 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, mut opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); |         let element_ty = self.element(); | ||||||
|         let element = self.element(); |         let element_size = element_ty.canonical().size(); | ||||||
|         let element_bit_width = element.canonical().bit_width(); |         let mut value = Vec::with_capacity(self.len()); | ||||||
|         TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| { |         for _ in 0..self.len() { | ||||||
|             SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width]) |             let (element_opaque, rest) = opaque.split_at(element_size); | ||||||
|         }))) |             value.push(SimValue::from_opaque(element_ty, element_opaque.to_owned())); | ||||||
|         .ok() |             opaque = rest; | ||||||
|         .expect("used correct length") |         } | ||||||
|  |         value.try_into().ok().expect("used correct length") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         mut opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|         let element_ty = self.element(); |         let element_ty = self.element(); | ||||||
|         let element_bit_width = element_ty.canonical().bit_width(); |         let element_size = element_ty.canonical().size(); | ||||||
|         let value: &mut [SimValue<T>] = value.as_mut(); |         let value = AsMut::<[SimValue<T>]>::as_mut(value); | ||||||
|         assert_eq!(self.len(), value.len()); |         assert_eq!(self.len(), value.len()); | ||||||
|         for (i, element_value) in value.iter_mut().enumerate() { |         for element_value in value { | ||||||
|             assert_eq!(SimValue::ty(element_value), element_ty); |             assert_eq!(SimValue::ty(element_value), element_ty); | ||||||
|             SimValue::bits_mut(element_value) |             let (element_opaque, rest) = opaque.split_at(element_size); | ||||||
|                 .bits_mut() |             SimValue::opaque_mut(element_value).clone_from_slice(element_opaque); | ||||||
|                 .copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]); |             opaque = rest; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         mut writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|         let element_ty = self.element(); |         let element_ty = self.element(); | ||||||
|         let element_bit_width = element_ty.canonical().bit_width(); |         let element_size = element_ty.canonical().size(); | ||||||
|         let value: &[SimValue<T>] = value.as_ref(); |         let value = AsRef::<[SimValue<T>]>::as_ref(value); | ||||||
|         assert_eq!(self.len(), value.len()); |         assert_eq!(self.len(), value.len()); | ||||||
|         for (i, element_value) in value.iter().enumerate() { |         for element_value in value { | ||||||
|             assert_eq!(SimValue::ty(element_value), element_ty); |             assert_eq!(SimValue::ty(element_value), element_ty); | ||||||
|             bits[i * element_bit_width..][..element_bit_width] |             writer.fill_prefix_with(element_size, |writer| { | ||||||
|                 .copy_from_bitslice(SimValue::bits(element_value).bits()); |                 writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice()) | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,12 +11,12 @@ use crate::{ | ||||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, |     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, StaticType, Type, TypeProperties, |         CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize, | ||||||
|         TypeWithDeref, impl_match_variant_as_self, |         OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, | ||||||
|  |         TypeProperties, TypeWithDeref, impl_match_variant_as_self, | ||||||
|     }, |     }, | ||||||
|     util::HashMap, |     util::HashMap, | ||||||
| }; | }; | ||||||
| use bitvec::{slice::BitSlice, vec::BitVec}; |  | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use std::{fmt, marker::PhantomData}; | use std::{fmt, marker::PhantomData}; | ||||||
| 
 | 
 | ||||||
|  | @ -69,7 +69,7 @@ impl fmt::Display for FmtDebugInStruct { | ||||||
| struct BundleImpl { | struct BundleImpl { | ||||||
|     fields: Interned<[BundleField]>, |     fields: Interned<[BundleField]>, | ||||||
|     name_indexes: HashMap<Interned<str>, usize>, |     name_indexes: HashMap<Interned<str>, usize>, | ||||||
|     field_offsets: Interned<[usize]>, |     field_offsets: Interned<[OpaqueSimValueSize]>, | ||||||
|     type_properties: TypeProperties, |     type_properties: TypeProperties, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -89,12 +89,9 @@ impl std::fmt::Debug for BundleImpl { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         f.write_str("Bundle ")?; |         f.write_str("Bundle ")?; | ||||||
|         f.debug_set() |         f.debug_set() | ||||||
|             .entries( |             .entries(self.fields.iter().enumerate().map(|(index, field)| { | ||||||
|                 self.fields |                 field.fmt_debug_in_struct(self.field_offsets[index].bit_width) | ||||||
|                     .iter() |             })) | ||||||
|                     .enumerate() |  | ||||||
|                     .map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])), |  | ||||||
|             ) |  | ||||||
|             .finish() |             .finish() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -119,6 +116,7 @@ impl BundleTypePropertiesBuilder { | ||||||
|             is_storable: true, |             is_storable: true, | ||||||
|             is_castable_from_bits: true, |             is_castable_from_bits: true, | ||||||
|             bit_width: 0, |             bit_width: 0, | ||||||
|  |             sim_only_values_len: 0, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|     pub const fn clone(&self) -> Self { |     pub const fn clone(&self) -> Self { | ||||||
|  | @ -126,8 +124,12 @@ impl BundleTypePropertiesBuilder { | ||||||
|     } |     } | ||||||
|     #[must_use] |     #[must_use] | ||||||
|     pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self { |     pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self { | ||||||
|         let Some(bit_width) = self.0.bit_width.checked_add(field_props.bit_width) else { |         let Some(OpaqueSimValueSize { | ||||||
|             panic!("bundle is too big: bit-width overflowed"); |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         }) = self.0.size().checked_add(field_props.size()) | ||||||
|  |         else { | ||||||
|  |             panic!("bundle is too big: size overflowed"); | ||||||
|         }; |         }; | ||||||
|         if flipped { |         if flipped { | ||||||
|             Self(TypeProperties { |             Self(TypeProperties { | ||||||
|  | @ -135,6 +137,7 @@ impl BundleTypePropertiesBuilder { | ||||||
|                 is_storable: false, |                 is_storable: false, | ||||||
|                 is_castable_from_bits: false, |                 is_castable_from_bits: false, | ||||||
|                 bit_width, |                 bit_width, | ||||||
|  |                 sim_only_values_len, | ||||||
|             }) |             }) | ||||||
|         } else { |         } else { | ||||||
|             Self(TypeProperties { |             Self(TypeProperties { | ||||||
|  | @ -143,6 +146,7 @@ impl BundleTypePropertiesBuilder { | ||||||
|                 is_castable_from_bits: self.0.is_castable_from_bits |                 is_castable_from_bits: self.0.is_castable_from_bits | ||||||
|                     & field_props.is_castable_from_bits, |                     & field_props.is_castable_from_bits, | ||||||
|                 bit_width, |                 bit_width, | ||||||
|  |                 sim_only_values_len, | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -167,7 +171,7 @@ impl Bundle { | ||||||
|             if let Some(old_index) = name_indexes.insert(name, index) { |             if let Some(old_index) = name_indexes.insert(name, index) { | ||||||
|                 panic!("duplicate field name {name:?}: at both index {old_index} and {index}"); |                 panic!("duplicate field name {name:?}: at both index {old_index} and {index}"); | ||||||
|             } |             } | ||||||
|             field_offsets.push(type_props_builder.0.bit_width); |             field_offsets.push(type_props_builder.0.size()); | ||||||
|             type_props_builder = type_props_builder.field(flipped, ty.type_properties()); |             type_props_builder = type_props_builder.field(flipped, ty.type_properties()); | ||||||
|         } |         } | ||||||
|         Self(Intern::intern_sized(BundleImpl { |         Self(Intern::intern_sized(BundleImpl { | ||||||
|  | @ -183,7 +187,7 @@ impl Bundle { | ||||||
|     pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> { |     pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> { | ||||||
|         Some(self.0.fields[*self.0.name_indexes.get(&name)?]) |         Some(self.0.fields[*self.0.name_indexes.get(&name)?]) | ||||||
|     } |     } | ||||||
|     pub fn field_offsets(self) -> Interned<[usize]> { |     pub fn field_offsets(self) -> Interned<[OpaqueSimValueSize]> { | ||||||
|         self.0.field_offsets |         self.0.field_offsets | ||||||
|     } |     } | ||||||
|     pub fn type_properties(self) -> TypeProperties { |     pub fn type_properties(self) -> TypeProperties { | ||||||
|  | @ -241,19 +245,27 @@ impl Type for Bundle { | ||||||
|     fn source_location() -> SourceLocation { |     fn source_location() -> SourceLocation { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|         OpaqueSimValue::from_bitslice(bits) |         opaque.to_owned() | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); |         value: &mut Self::SimValue, | ||||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|  |         assert_eq!(value.size(), opaque.size()); | ||||||
|  |         value.clone_from_slice(opaque); | ||||||
|     } |     } | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); |         value: &Self::SimValue, | ||||||
|         bits.copy_from_bitslice(value.bits().bits()); |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         assert_eq!(self.type_properties().size(), writer.size()); | ||||||
|  |         assert_eq!(value.size(), writer.size()); | ||||||
|  |         writer.fill_cloned_from_slice(value.as_slice()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -263,29 +275,29 @@ pub trait BundleType: Type<BaseType = Bundle> { | ||||||
|     fn fields(&self) -> Interned<[BundleField]>; |     fn fields(&self) -> Interned<[BundleField]>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct BundleSimValueFromBits<'a> { | pub struct BundleSimValueFromOpaque<'a> { | ||||||
|     fields: std::slice::Iter<'static, BundleField>, |     fields: std::slice::Iter<'static, BundleField>, | ||||||
|     bits: &'a BitSlice, |     opaque: OpaqueSimValueSlice<'a>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> BundleSimValueFromBits<'a> { | impl<'a> BundleSimValueFromOpaque<'a> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn new<T: BundleType>(bundle_ty: T, bits: &'a BitSlice) -> Self { |     pub fn new<T: BundleType>(bundle_ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self { | ||||||
|         let fields = bundle_ty.fields(); |         let fields = bundle_ty.fields(); | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             bits.len(), |             opaque.size(), | ||||||
|             fields |             fields | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .map(|BundleField { ty, .. }| ty.bit_width()) |                 .map(|BundleField { ty, .. }| ty.size()) | ||||||
|                 .sum::<usize>() |                 .sum::<OpaqueSimValueSize>() | ||||||
|         ); |         ); | ||||||
|         Self { |         Self { | ||||||
|             fields: Interned::into_inner(fields).iter(), |             fields: Interned::into_inner(fields).iter(), | ||||||
|             bits, |             opaque, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn field_ty_and_bits<T: Type>(&mut self) -> (T, &'a BitSlice) { |     fn field_ty_and_opaque<T: Type>(&mut self) -> (T, OpaqueSimValueSlice<'a>) { | ||||||
|         let Some(&BundleField { |         let Some(&BundleField { | ||||||
|             name: _, |             name: _, | ||||||
|             flipped: _, |             flipped: _, | ||||||
|  | @ -294,59 +306,68 @@ impl<'a> BundleSimValueFromBits<'a> { | ||||||
|         else { |         else { | ||||||
|             panic!("tried to read too many fields from BundleSimValueFromBits"); |             panic!("tried to read too many fields from BundleSimValueFromBits"); | ||||||
|         }; |         }; | ||||||
|         let (field_bits, rest) = self.bits.split_at(ty.bit_width()); |         let (field_opaque, rest) = self.opaque.split_at(ty.size()); | ||||||
|         self.bits = rest; |         self.opaque = rest; | ||||||
|         (T::from_canonical(ty), field_bits) |         (T::from_canonical(ty), field_opaque) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn field_from_bits<T: Type>(&mut self) -> SimValue<T> { |     pub fn field_from_opaque<T: Type>(&mut self) -> SimValue<T> { | ||||||
|         let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); |         let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>(); | ||||||
|         SimValue::from_bitslice(field_ty, field_bits) |         SimValue::from_opaque(field_ty, field_opaque.to_owned()) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn field_clone_from_bits<T: Type>(&mut self, field_value: &mut SimValue<T>) { |     pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) { | ||||||
|         let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); |         let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>(); | ||||||
|         assert_eq!(field_ty, SimValue::ty(field_value)); |         assert_eq!(field_ty, SimValue::ty(field_value)); | ||||||
|         SimValue::bits_mut(field_value) |         SimValue::opaque_mut(field_value).clone_from_slice(field_opaque); | ||||||
|             .bits_mut() |  | ||||||
|             .copy_from_bitslice(field_bits); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct BundleSimValueToBits<'a> { | pub struct BundleSimValueToOpaque<'a> { | ||||||
|     fields: std::slice::Iter<'static, BundleField>, |     fields: std::slice::Iter<'static, BundleField>, | ||||||
|     bits: &'a mut BitSlice, |     writer: OpaqueSimValueWriter<'a>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> BundleSimValueToBits<'a> { | impl<'a> BundleSimValueToOpaque<'a> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn new<T: BundleType>(bundle_ty: T, bits: &'a mut BitSlice) -> Self { |     pub fn new<T: BundleType>(bundle_ty: T, writer: OpaqueSimValueWriter<'a>) -> Self { | ||||||
|         let fields = bundle_ty.fields(); |         let fields = bundle_ty.fields(); | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             bits.len(), |             writer.size(), | ||||||
|             fields |             fields | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .map(|BundleField { ty, .. }| ty.bit_width()) |                 .map(|BundleField { ty, .. }| ty.size()) | ||||||
|                 .sum::<usize>() |                 .sum::<OpaqueSimValueSize>() | ||||||
|         ); |         ); | ||||||
|         Self { |         Self { | ||||||
|             fields: Interned::into_inner(fields).iter(), |             fields: Interned::into_inner(fields).iter(), | ||||||
|             bits, |             writer, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn field_to_bits<T: Type>(&mut self, field_value: &SimValue<T>) { |     pub fn field<T: Type>(&mut self, field_value: &SimValue<T>) { | ||||||
|         let Some(&BundleField { |         let Some(&BundleField { | ||||||
|             name: _, |             name: _, | ||||||
|             flipped: _, |             flipped: _, | ||||||
|             ty, |             ty, | ||||||
|         }) = self.fields.next() |         }) = self.fields.next() | ||||||
|         else { |         else { | ||||||
|             panic!("tried to read too many fields from BundleSimValueFromBits"); |             panic!("tried to write too many fields with BundleSimValueToOpaque"); | ||||||
|         }; |         }; | ||||||
|         assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); |         assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); | ||||||
|         self.bits[..ty.bit_width()].copy_from_bitslice(SimValue::bits(field_value).bits()); |         self.writer.fill_prefix_with(ty.size(), |writer| { | ||||||
|         self.bits = &mut std::mem::take(&mut self.bits)[ty.bit_width()..]; |             writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice()) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     pub fn finish(mut self) -> OpaqueSimValueWritten<'a> { | ||||||
|  |         assert_eq!( | ||||||
|  |             self.fields.next(), | ||||||
|  |             None, | ||||||
|  |             "wrote too few fields with BundleSimValueToOpaque" | ||||||
|  |         ); | ||||||
|  |         self.writer | ||||||
|  |             .fill_cloned_from_slice(OpaqueSimValueSlice::empty()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -495,23 +516,32 @@ macro_rules! impl_tuples { | ||||||
|             fn source_location() -> SourceLocation { |             fn source_location() -> SourceLocation { | ||||||
|                 SourceLocation::builtin() |                 SourceLocation::builtin() | ||||||
|             } |             } | ||||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|                 #![allow(unused_mut, unused_variables)] |                 #![allow(unused_mut, unused_variables)] | ||||||
|                 let mut v = BundleSimValueFromBits::new(*self, bits); |                 let mut v = BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                 $(let $var = v.field_from_bits();)* |                 $(let $var = v.field_from_opaque();)* | ||||||
|                 ($($var,)*) |                 ($($var,)*) | ||||||
|             } |             } | ||||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |             fn sim_value_clone_from_opaque( | ||||||
|  |                 &self, | ||||||
|  |                 value: &mut Self::SimValue, | ||||||
|  |                 opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |             ) { | ||||||
|                 #![allow(unused_mut, unused_variables)] |                 #![allow(unused_mut, unused_variables)] | ||||||
|                 let mut v = BundleSimValueFromBits::new(*self, bits); |                 let mut v = BundleSimValueFromOpaque::new(*self, opaque); | ||||||
|                 let ($($var,)*) = value; |                 let ($($var,)*) = value; | ||||||
|                 $(v.field_clone_from_bits($var);)* |                 $(v.field_clone_from_opaque($var);)* | ||||||
|             } |             } | ||||||
|             fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |             fn sim_value_to_opaque<'w>( | ||||||
|  |                 &self, | ||||||
|  |                 value: &Self::SimValue, | ||||||
|  |                 writer: OpaqueSimValueWriter<'w>, | ||||||
|  |             ) -> OpaqueSimValueWritten<'w> { | ||||||
|                 #![allow(unused_mut, unused_variables)] |                 #![allow(unused_mut, unused_variables)] | ||||||
|                 let mut v = BundleSimValueToBits::new(*self, bits); |                 let mut v = BundleSimValueToOpaque::new(*self, writer); | ||||||
|                 let ($($var,)*) = value; |                 let ($($var,)*) = value; | ||||||
|                 $(v.field_to_bits($var);)* |                 $(v.field($var);)* | ||||||
|  |                 v.finish() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         impl<$($T: Type,)*> BundleType for ($($T,)*) { |         impl<$($T: Type,)*> BundleType for ($($T,)*) { | ||||||
|  | @ -592,12 +622,12 @@ macro_rules! impl_tuples { | ||||||
|                 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 mut bits = BitVec::new(); |                 let mut opaque = OpaqueSimValue::empty(); | ||||||
|                 $(let $var = $var.into_sim_value_with_type($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()); |                 opaque.extend_from_slice(SimValue::opaque(&$var).as_slice()); | ||||||
|                 )* |                 )* | ||||||
|                 bits.into_sim_value_with_type(ty) |                 SimValue::from_opaque(ty, opaque) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { |         impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { | ||||||
|  | @ -723,15 +753,23 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | ||||||
|     fn source_location() -> SourceLocation { |     fn source_location() -> SourceLocation { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert!(bits.is_empty()); |         assert!(opaque.is_empty()); | ||||||
|         *self |         *self | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert!(bits.is_empty()); |         &self, | ||||||
|  |         _value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert!(opaque.is_empty()); | ||||||
|     } |     } | ||||||
|     fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert!(bits.is_empty()); |         &self, | ||||||
|  |         _value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -800,18 +838,15 @@ impl<T: ?Sized> ToSimValueWithType<Bundle> for PhantomData<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { |     fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|         assert!(ty.fields().is_empty()); |         assert!(ty.fields().is_empty()); | ||||||
|         ToSimValueWithType::into_sim_value_with_type(BitVec::new(), ty) |         SimValue::from_opaque(ty, OpaqueSimValue::empty()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> { | impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { |     fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|         let ty = Bundle::from_canonical(ty); |         let ty = Bundle::from_canonical(canonical_ty); | ||||||
|         assert!(ty.fields().is_empty()); |         assert!(ty.fields().is_empty()); | ||||||
|         SimValue::into_canonical(ToSimValueWithType::into_sim_value_with_type( |         SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty()) | ||||||
|             BitVec::new(), |  | ||||||
|             ty, |  | ||||||
|         )) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,9 +6,12 @@ use crate::{ | ||||||
|     int::Bool, |     int::Bool, | ||||||
|     reset::{Reset, ResetType}, |     reset::{Reset, ResetType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, |     ty::{ | ||||||
|  |         CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, | ||||||
|  |         OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|  |     }, | ||||||
| }; | }; | ||||||
| use bitvec::slice::BitSlice; | use bitvec::{bits, order::Lsb0}; | ||||||
| 
 | 
 | ||||||
| #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] | ||||||
| pub struct Clock; | pub struct Clock; | ||||||
|  | @ -39,19 +42,29 @@ impl Type for Clock { | ||||||
|         retval |         retval | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), 1); |         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|         bits[0] |         opaque.bits()[0] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), 1); |         &self, | ||||||
|         *value = bits[0]; |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |         *value = opaque.bits()[0]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), 1); |         &self, | ||||||
|         bits.set(0, *value); |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( | ||||||
|  |             [bits![0], bits![1]][*value as usize], | ||||||
|  |         )) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -72,6 +85,7 @@ impl StaticType for Clock { | ||||||
|         is_storable: false, |         is_storable: false, | ||||||
|         is_castable_from_bits: true, |         is_castable_from_bits: true, | ||||||
|         bit_width: 1, |         bit_width: 1, | ||||||
|  |         sim_only_values_len: 0, | ||||||
|     }; |     }; | ||||||
|     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; |     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,7 +16,8 @@ use crate::{ | ||||||
|     sim::value::{SimValue, SimValuePartialEq}, |     sim::value::{SimValue, SimValuePartialEq}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type, |         CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize, | ||||||
|  |         OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, | ||||||
|         TypeProperties, |         TypeProperties, | ||||||
|     }, |     }, | ||||||
|     util::HashMap, |     util::HashMap, | ||||||
|  | @ -120,6 +121,7 @@ impl EnumTypePropertiesBuilder { | ||||||
|                 is_storable: true, |                 is_storable: true, | ||||||
|                 is_castable_from_bits: true, |                 is_castable_from_bits: true, | ||||||
|                 bit_width: 0, |                 bit_width: 0, | ||||||
|  |                 sim_only_values_len: 0, | ||||||
|             }, |             }, | ||||||
|             variant_count: 0, |             variant_count: 0, | ||||||
|         } |         } | ||||||
|  | @ -138,9 +140,14 @@ impl EnumTypePropertiesBuilder { | ||||||
|             is_storable, |             is_storable, | ||||||
|             is_castable_from_bits, |             is_castable_from_bits, | ||||||
|             bit_width, |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|         }) = field_props |         }) = field_props | ||||||
|         { |         { | ||||||
|             assert!(is_passive, "variant type must be a passive type"); |             assert!(is_passive, "variant type must be a passive type"); | ||||||
|  |             assert!( | ||||||
|  |                 sim_only_values_len == 0, | ||||||
|  |                 "can't have `SimOnlyValue`s in an Enum" | ||||||
|  |             ); | ||||||
|             type_properties = TypeProperties { |             type_properties = TypeProperties { | ||||||
|                 is_passive: true, |                 is_passive: true, | ||||||
|                 is_storable: type_properties.is_storable & is_storable, |                 is_storable: type_properties.is_storable & is_storable, | ||||||
|  | @ -151,6 +158,7 @@ impl EnumTypePropertiesBuilder { | ||||||
|                 } else { |                 } else { | ||||||
|                     type_properties.bit_width |                     type_properties.bit_width | ||||||
|                 }, |                 }, | ||||||
|  |                 sim_only_values_len: 0, | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|         Self { |         Self { | ||||||
|  | @ -381,19 +389,27 @@ impl Type for Enum { | ||||||
|     fn source_location() -> SourceLocation { |     fn source_location() -> SourceLocation { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|         OpaqueSimValue::from_bitslice(bits) |         opaque.to_owned() | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); |         value: &mut Self::SimValue, | ||||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|  |         assert_eq!(value.size(), opaque.size()); | ||||||
|  |         value.clone_from_slice(opaque); | ||||||
|     } |     } | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); |         value: &Self::SimValue, | ||||||
|         bits.copy_from_bitslice(value.bits().bits()); |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         assert_eq!(self.type_properties().size(), writer.size()); | ||||||
|  |         assert_eq!(value.size(), writer.size()); | ||||||
|  |         writer.fill_cloned_from_slice(value.as_slice()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -458,23 +474,30 @@ impl UnknownVariantSimValue { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct EnumSimValueFromBits<'a> { | pub struct EnumSimValueFromOpaque<'a> { | ||||||
|     variants: Interned<[EnumVariant]>, |     variants: Interned<[EnumVariant]>, | ||||||
|     discriminant: usize, |     discriminant: usize, | ||||||
|     body_bits: &'a BitSlice, |     body_bits: &'a BitSlice, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> EnumSimValueFromBits<'a> { | impl<'a> EnumSimValueFromOpaque<'a> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn new<T: EnumType>(ty: T, bits: &'a BitSlice) -> Self { |     pub fn new<T: EnumType>(ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self { | ||||||
|         let variants = ty.variants(); |         let variants = ty.variants(); | ||||||
|         let bit_width = EnumTypePropertiesBuilder::new() |         let size @ OpaqueSimValueSize { | ||||||
|  |             bit_width: _, | ||||||
|  |             sim_only_values_len: 0, | ||||||
|  |         } = EnumTypePropertiesBuilder::new() | ||||||
|             .variants(variants) |             .variants(variants) | ||||||
|             .finish() |             .finish() | ||||||
|             .bit_width; |             .size() | ||||||
|         assert_eq!(bit_width, bits.len()); |         else { | ||||||
|         let (discriminant_bits, body_bits) = |             unreachable!(); | ||||||
|             bits.split_at(discriminant_bit_width_impl(variants.len())); |         }; | ||||||
|  |         assert_eq!(size, opaque.size()); | ||||||
|  |         let (discriminant_bits, body_bits) = opaque | ||||||
|  |             .bits() | ||||||
|  |             .split_at(discriminant_bit_width_impl(variants.len())); | ||||||
|         let mut discriminant = 0usize; |         let mut discriminant = 0usize; | ||||||
|         discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()] |         discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()] | ||||||
|             .copy_from_bitslice(discriminant_bits); |             .copy_from_bitslice(discriminant_bits); | ||||||
|  | @ -517,7 +540,7 @@ impl<'a> EnumSimValueFromBits<'a> { | ||||||
|         (*ty, variant_bits, padding_bits) |         (*ty, variant_bits, padding_bits) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn unknown_variant_from_bits(self) -> UnknownVariantSimValue { |     pub fn unknown_variant_from_opaque(self) -> UnknownVariantSimValue { | ||||||
|         let None = self.variants.get(self.discriminant) else { |         let None = self.variants.get(self.discriminant) else { | ||||||
|             self.usage_error(false); |             self.usage_error(false); | ||||||
|         }; |         }; | ||||||
|  | @ -527,7 +550,7 @@ impl<'a> EnumSimValueFromBits<'a> { | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn unknown_variant_clone_from_bits(self, value: &mut UnknownVariantSimValue) { |     pub fn unknown_variant_clone_from_opaque(self, value: &mut UnknownVariantSimValue) { | ||||||
|         let None = self.variants.get(self.discriminant) else { |         let None = self.variants.get(self.discriminant) else { | ||||||
|             self.usage_error(true); |             self.usage_error(true); | ||||||
|         }; |         }; | ||||||
|  | @ -539,14 +562,14 @@ impl<'a> EnumSimValueFromBits<'a> { | ||||||
|             .copy_from_bitslice(self.body_bits); |             .copy_from_bitslice(self.body_bits); | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_no_field_from_bits(self) -> EnumPaddingSimValue { |     pub fn variant_no_field_from_opaque(self) -> EnumPaddingSimValue { | ||||||
|         let (None, _variant_bits, padding_bits) = self.known_variant(false) else { |         let (None, _variant_bits, padding_bits) = self.known_variant(false) else { | ||||||
|             self.usage_error(false); |             self.usage_error(false); | ||||||
|         }; |         }; | ||||||
|         EnumPaddingSimValue::from_bitslice(padding_bits) |         EnumPaddingSimValue::from_bitslice(padding_bits) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_with_field_from_bits<T: Type>(self) -> (SimValue<T>, EnumPaddingSimValue) { |     pub fn variant_with_field_from_opaque<T: Type>(self) -> (SimValue<T>, EnumPaddingSimValue) { | ||||||
|         let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { |         let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { | ||||||
|             self.usage_error(false); |             self.usage_error(false); | ||||||
|         }; |         }; | ||||||
|  | @ -566,14 +589,14 @@ impl<'a> EnumSimValueFromBits<'a> { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_no_field_clone_from_bits(self, padding: &mut EnumPaddingSimValue) { |     pub fn variant_no_field_clone_from_opaque(self, padding: &mut EnumPaddingSimValue) { | ||||||
|         let (None, _variant_bits, padding_bits) = self.known_variant(true) else { |         let (None, _variant_bits, padding_bits) = self.known_variant(true) else { | ||||||
|             self.usage_error(true); |             self.usage_error(true); | ||||||
|         }; |         }; | ||||||
|         Self::clone_padding_from_bits(padding, padding_bits); |         Self::clone_padding_from_bits(padding, padding_bits); | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_with_field_clone_from_bits<T: Type>( |     pub fn variant_with_field_clone_from_opaque<T: Type>( | ||||||
|         self, |         self, | ||||||
|         value: &mut SimValue<T>, |         value: &mut SimValue<T>, | ||||||
|         padding: &mut EnumPaddingSimValue, |         padding: &mut EnumPaddingSimValue, | ||||||
|  | @ -589,35 +612,46 @@ impl<'a> EnumSimValueFromBits<'a> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct EnumSimValueToBits<'a> { | pub struct EnumSimValueToOpaque<'a> { | ||||||
|     variants: Interned<[EnumVariant]>, |     variants: Interned<[EnumVariant]>, | ||||||
|     bit_width: usize, |     bit_width: usize, | ||||||
|     discriminant_bit_width: usize, |     discriminant_bit_width: usize, | ||||||
|     bits: &'a mut BitSlice, |     writer: OpaqueSimValueWriter<'a>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> EnumSimValueToBits<'a> { | impl<'a> EnumSimValueToOpaque<'a> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn new<T: EnumType>(ty: T, bits: &'a mut BitSlice) -> Self { |     pub fn new<T: EnumType>(ty: T, writer: OpaqueSimValueWriter<'a>) -> Self { | ||||||
|         let variants = ty.variants(); |         let variants = ty.variants(); | ||||||
|         let bit_width = EnumTypePropertiesBuilder::new() |         let size @ OpaqueSimValueSize { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len: 0, | ||||||
|  |         } = EnumTypePropertiesBuilder::new() | ||||||
|             .variants(variants) |             .variants(variants) | ||||||
|             .finish() |             .finish() | ||||||
|             .bit_width; |             .size() | ||||||
|         assert_eq!(bit_width, bits.len()); |         else { | ||||||
|  |             unreachable!(); | ||||||
|  |         }; | ||||||
|  |         assert_eq!(size, writer.size()); | ||||||
|         Self { |         Self { | ||||||
|             variants, |             variants, | ||||||
|             bit_width, |             bit_width, | ||||||
|             discriminant_bit_width: discriminant_bit_width_impl(variants.len()), |             discriminant_bit_width: discriminant_bit_width_impl(variants.len()), | ||||||
|             bits, |             writer, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn discriminant_to_bits(&mut self, mut discriminant: usize) { |     fn write_discriminant(&mut self, mut discriminant: usize) { | ||||||
|         let orig_discriminant = discriminant; |         let orig_discriminant = discriminant; | ||||||
|         let discriminant_bits = |         let discriminant_bits = | ||||||
|             &mut discriminant.view_bits_mut::<Lsb0>()[..self.discriminant_bit_width]; |             &mut discriminant.view_bits_mut::<Lsb0>()[..self.discriminant_bit_width]; | ||||||
|         self.bits[..self.discriminant_bit_width].copy_from_bitslice(discriminant_bits); |         self.writer.fill_prefix_with( | ||||||
|  |             OpaqueSimValueSize::from_bit_width(self.discriminant_bit_width), | ||||||
|  |             |writer| { | ||||||
|  |                 writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(discriminant_bits)) | ||||||
|  |             }, | ||||||
|  |         ); | ||||||
|         discriminant_bits.fill(false); |         discriminant_bits.fill(false); | ||||||
|         assert!( |         assert!( | ||||||
|             discriminant == 0, |             discriminant == 0, | ||||||
|  | @ -625,8 +659,11 @@ impl<'a> EnumSimValueToBits<'a> { | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn unknown_variant_to_bits(mut self, value: &UnknownVariantSimValue) { |     pub fn unknown_variant_to_opaque( | ||||||
|         self.discriminant_to_bits(value.discriminant); |         mut self, | ||||||
|  |         value: &UnknownVariantSimValue, | ||||||
|  |     ) -> OpaqueSimValueWritten<'a> { | ||||||
|  |         self.write_discriminant(value.discriminant); | ||||||
|         let None = self.variants.get(value.discriminant) else { |         let None = self.variants.get(value.discriminant) else { | ||||||
|             panic!("can't use UnknownVariantSimValue to set known discriminant"); |             panic!("can't use UnknownVariantSimValue to set known discriminant"); | ||||||
|         }; |         }; | ||||||
|  | @ -634,45 +671,57 @@ impl<'a> EnumSimValueToBits<'a> { | ||||||
|             self.bit_width - self.discriminant_bit_width, |             self.bit_width - self.discriminant_bit_width, | ||||||
|             value.body_bits.width() |             value.body_bits.width() | ||||||
|         ); |         ); | ||||||
|         self.bits[self.discriminant_bit_width..].copy_from_bitslice(value.body_bits.bits()); |         self.writer | ||||||
|  |             .fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.body_bits.bits())) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn known_variant( |     fn known_variant( | ||||||
|         mut self, |         mut self, | ||||||
|         discriminant: usize, |         discriminant: usize, | ||||||
|  |         value: Option<&OpaqueSimValue>, | ||||||
|         padding: &EnumPaddingSimValue, |         padding: &EnumPaddingSimValue, | ||||||
|     ) -> (Option<CanonicalType>, &'a mut BitSlice) { |     ) -> OpaqueSimValueWritten<'a> { | ||||||
|         self.discriminant_to_bits(discriminant); |         self.write_discriminant(discriminant); | ||||||
|         let variant_ty = self.variants[discriminant].ty; |         let variant_ty = self.variants[discriminant].ty; | ||||||
|         let variant_bit_width = variant_ty.map_or(0, CanonicalType::bit_width); |         let variant_size = variant_ty.map_or(OpaqueSimValueSize::empty(), CanonicalType::size); | ||||||
|         let padding_bits = &mut self.bits[self.discriminant_bit_width..][variant_bit_width..]; |         if let Some(value) = value { | ||||||
|         if let Some(padding) = padding.bits() { |             if variant_ty.is_none() { | ||||||
|             assert_eq!(padding.width(), padding_bits.len()); |                 panic!("expected variant to have no field"); | ||||||
|             padding_bits.copy_from_bitslice(padding.bits()); |             } | ||||||
|         } else { |             self.writer.fill_prefix_with(variant_size, |writer| { | ||||||
|             padding_bits.fill(false); |                 writer.fill_cloned_from_slice(value.as_slice()) | ||||||
|  |             }); | ||||||
|  |         } else if variant_ty.is_some() { | ||||||
|  |             panic!("expected variant to have a field"); | ||||||
|  |         } | ||||||
|  |         if let Some(padding) = padding.bits() { | ||||||
|  |             assert_eq!(padding.ty().type_properties().size(), self.writer.size()); | ||||||
|  |             self.writer | ||||||
|  |                 .fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(padding.bits())) | ||||||
|  |         } else { | ||||||
|  |             self.writer.fill_with_zeros() | ||||||
|         } |         } | ||||||
|         let variant_bits = &mut self.bits[self.discriminant_bit_width..][..variant_bit_width]; |  | ||||||
|         (variant_ty, variant_bits) |  | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_no_field_to_bits(self, discriminant: usize, padding: &EnumPaddingSimValue) { |     pub fn variant_no_field_to_opaque( | ||||||
|         let (None, _variant_bits) = self.known_variant(discriminant, padding) else { |         self, | ||||||
|             panic!("expected variant to have no field"); |         discriminant: usize, | ||||||
|         }; |         padding: &EnumPaddingSimValue, | ||||||
|  |     ) -> OpaqueSimValueWritten<'a> { | ||||||
|  |         self.known_variant(discriminant, None, padding) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn variant_with_field_to_bits<T: Type>( |     pub fn variant_with_field_to_opaque<T: Type>( | ||||||
|         self, |         self, | ||||||
|         discriminant: usize, |         discriminant: usize, | ||||||
|         value: &SimValue<T>, |         value: &SimValue<T>, | ||||||
|         padding: &EnumPaddingSimValue, |         padding: &EnumPaddingSimValue, | ||||||
|     ) { |     ) -> OpaqueSimValueWritten<'a> { | ||||||
|         let (Some(variant_ty), variant_bits) = self.known_variant(discriminant, padding) else { |         let Some(variant_ty) = self.variants[discriminant].ty else { | ||||||
|             panic!("expected variant to have a field"); |             panic!("expected variant to have no field"); | ||||||
|         }; |         }; | ||||||
|         assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); |         assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); | ||||||
|         variant_bits.copy_from_bitslice(SimValue::bits(value).bits()); |         self.known_variant(discriminant, Some(SimValue::opaque(value)), padding) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1937,7 +1937,8 @@ impl<FieldType: Type> FieldAccess<FieldType> { | ||||||
|         let field = Expr::ty(base).fields()[field_index]; |         let field = Expr::ty(base).fields()[field_index]; | ||||||
|         let field_type = FieldType::from_canonical(field.ty); |         let field_type = FieldType::from_canonical(field.ty); | ||||||
|         let literal_bits = base.to_literal_bits().map(|bits| { |         let literal_bits = base.to_literal_bits().map(|bits| { | ||||||
|             bits[Expr::ty(base).field_offsets()[field_index]..][..field.ty.bit_width()].intern() |             bits[Expr::ty(base).field_offsets()[field_index].bit_width..][..field.ty.bit_width()] | ||||||
|  |                 .intern() | ||||||
|         }); |         }); | ||||||
|         let target = base.target().map(|base| { |         let target = base.target().map(|base| { | ||||||
|             Intern::intern_sized(base.join(TargetPathElement::intern_sized( |             Intern::intern_sized(base.join(TargetPathElement::intern_sized( | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -11,10 +11,13 @@ use crate::{ | ||||||
|     intern::{Intern, Interned, Memoize}, |     intern::{Intern, Interned, Memoize}, | ||||||
|     sim::value::{SimValue, ToSimValueWithType}, |     sim::value::{SimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, |     ty::{ | ||||||
|     util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit}, |         CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, | ||||||
|  |         OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|  |     }, | ||||||
|  |     util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit, slice_range}, | ||||||
| }; | }; | ||||||
| use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; | use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; | ||||||
| use num_bigint::{BigInt, BigUint, Sign}; | use num_bigint::{BigInt, BigUint, Sign}; | ||||||
| use num_traits::{One, Signed, Zero}; | use num_traits::{One, Signed, Zero}; | ||||||
| use serde::{ | use serde::{ | ||||||
|  | @ -26,7 +29,7 @@ use std::{ | ||||||
|     fmt, |     fmt, | ||||||
|     marker::PhantomData, |     marker::PhantomData, | ||||||
|     num::NonZero, |     num::NonZero, | ||||||
|     ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive}, |     ops::{Index, Not, Range, RangeBounds, RangeInclusive}, | ||||||
|     str::FromStr, |     str::FromStr, | ||||||
|     sync::Arc, |     sync::Arc, | ||||||
| }; | }; | ||||||
|  | @ -645,6 +648,7 @@ macro_rules! impl_int { | ||||||
|                     is_storable: true, |                     is_storable: true, | ||||||
|                     is_castable_from_bits: true, |                     is_castable_from_bits: true, | ||||||
|                     bit_width: self.width, |                     bit_width: self.width, | ||||||
|  |                     sim_only_values_len: 0, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -678,19 +682,36 @@ macro_rules! impl_int { | ||||||
|             fn source_location() -> SourceLocation { |             fn source_location() -> SourceLocation { | ||||||
|                 SourceLocation::builtin() |                 SourceLocation::builtin() | ||||||
|             } |             } | ||||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|                 assert_eq!(bits.len(), self.width()); |                 assert_eq!( | ||||||
|                 $value::new(Arc::new(bits.to_bitvec())) |                     opaque.size(), | ||||||
|  |                     OpaqueSimValueSize::from_bit_width(self.width()) | ||||||
|  |                 ); | ||||||
|  |                 $value::new(Arc::new(opaque.bits().to_bitvec())) | ||||||
|             } |             } | ||||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |             fn sim_value_clone_from_opaque( | ||||||
|                 assert_eq!(bits.len(), self.width()); |                 &self, | ||||||
|  |                 value: &mut Self::SimValue, | ||||||
|  |                 opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |             ) { | ||||||
|  |                 assert_eq!( | ||||||
|  |                     opaque.size(), | ||||||
|  |                     OpaqueSimValueSize::from_bit_width(self.width()) | ||||||
|  |                 ); | ||||||
|                 assert_eq!(value.width(), self.width()); |                 assert_eq!(value.width(), self.width()); | ||||||
|                 value.bits_mut().copy_from_bitslice(bits); |                 value.bits_mut().copy_from_bitslice(opaque.bits()); | ||||||
|             } |             } | ||||||
|             fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |             fn sim_value_to_opaque<'w>( | ||||||
|                 assert_eq!(bits.len(), self.width()); |                 &self, | ||||||
|  |                 value: &Self::SimValue, | ||||||
|  |                 writer: OpaqueSimValueWriter<'w>, | ||||||
|  |             ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |                 assert_eq!( | ||||||
|  |                     writer.size(), | ||||||
|  |                     OpaqueSimValueSize::from_bit_width(self.width()) | ||||||
|  |                 ); | ||||||
|                 assert_eq!(value.width(), self.width()); |                 assert_eq!(value.width(), self.width()); | ||||||
|                 bits.copy_from_bitslice(value.bits()); |                 writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.bits())) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -898,6 +919,9 @@ macro_rules! impl_int { | ||||||
|                     _phantom: PhantomData, |                     _phantom: PhantomData, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             pub fn bitvec_mut(&mut self) -> &mut BitVec { | ||||||
|  |                 Arc::make_mut(&mut self.bits) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  | @ -1160,19 +1184,7 @@ pub trait IntType: | ||||||
|         Self::Dyn::new(width) |         Self::Dyn::new(width) | ||||||
|     } |     } | ||||||
|     fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> { |     fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> { | ||||||
|         let width = self.width(); |         slice_range(index, self.width()) | ||||||
|         let start = match index.start_bound() { |  | ||||||
|             Bound::Included(start) => *start, |  | ||||||
|             Bound::Excluded(start) => *start + 1, |  | ||||||
|             Bound::Unbounded => 0, |  | ||||||
|         }; |  | ||||||
|         let end = match index.end_bound() { |  | ||||||
|             Bound::Included(end) => *end + 1, |  | ||||||
|             Bound::Excluded(end) => *end, |  | ||||||
|             Bound::Unbounded => width, |  | ||||||
|         }; |  | ||||||
|         assert!(start <= end && end <= width, "slice range out-of-range"); |  | ||||||
|         start..end |  | ||||||
|     } |     } | ||||||
|     fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) { |     fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) { | ||||||
|         let range = self.slice_index_to_range(index); |         let range = self.slice_index_to_range(index); | ||||||
|  | @ -1252,17 +1264,27 @@ impl Type for Bool { | ||||||
|     fn source_location() -> SourceLocation { |     fn source_location() -> SourceLocation { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), 1); |         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|         bits[0] |         opaque.bits()[0] | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), 1); |         &self, | ||||||
|         *value = bits[0]; |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |         *value = opaque.bits()[0]; | ||||||
|     } |     } | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), 1); |         &self, | ||||||
|         bits.set(0, *value); |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( | ||||||
|  |             [bits![0], bits![1]][*value as usize], | ||||||
|  |         )) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1274,6 +1296,7 @@ impl StaticType for Bool { | ||||||
|         is_storable: true, |         is_storable: true, | ||||||
|         is_castable_from_bits: true, |         is_castable_from_bits: true, | ||||||
|         bit_width: 1, |         bit_width: 1, | ||||||
|  |         sim_only_values_len: 0, | ||||||
|     }; |     }; | ||||||
|     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; |     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,9 +12,12 @@ use crate::{ | ||||||
|     phantom_const::PhantomConst, |     phantom_const::PhantomConst, | ||||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, |     sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, |     ty::{ | ||||||
|  |         CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, | ||||||
|  |         StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|  |     }, | ||||||
| }; | }; | ||||||
| use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; | use bitvec::{order::Lsb0, view::BitView}; | ||||||
| use serde::{ | use serde::{ | ||||||
|     Deserialize, Deserializer, Serialize, Serializer, |     Deserialize, Deserializer, Serialize, Serializer, | ||||||
|     de::{Error, Visitor, value::UsizeDeserializer}, |     de::{Error, Visitor, value::UsizeDeserializer}, | ||||||
|  | @ -70,16 +73,24 @@ impl Type for UIntInRangeMaskType { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         Bool.sim_value_from_bits(bits) |         Bool.sim_value_from_opaque(opaque) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         Bool.sim_value_clone_from_bits(value, bits); |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         Bool.sim_value_clone_from_opaque(value, opaque); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         Bool.sim_value_to_bits(value, bits); |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         Bool.sim_value_to_opaque(value, writer) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -353,18 +364,30 @@ macro_rules! define_uint_in_range_type { | ||||||
|                 SourceLocation::builtin() |                 SourceLocation::builtin() | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|  |                 assert_eq!(opaque.size(), self.value.type_properties().size()); | ||||||
|                 let mut retval = 0usize; |                 let mut retval = 0usize; | ||||||
|                 retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(bits); |                 retval.view_bits_mut::<Lsb0>()[..opaque.bit_width()] | ||||||
|  |                     .clone_from_bitslice(opaque.bits()); | ||||||
|                 retval |                 retval | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |             fn sim_value_clone_from_opaque( | ||||||
|                 *value = self.sim_value_from_bits(bits); |                 &self, | ||||||
|  |                 value: &mut Self::SimValue, | ||||||
|  |                 opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |             ) { | ||||||
|  |                 *value = self.sim_value_from_opaque(opaque); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |             fn sim_value_to_opaque<'w>( | ||||||
|                 bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]); |                 &self, | ||||||
|  |                 value: &Self::SimValue, | ||||||
|  |                 writer: OpaqueSimValueWriter<'w>, | ||||||
|  |             ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |                 writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( | ||||||
|  |                     &value.view_bits::<Lsb0>()[..self.value.width()], | ||||||
|  |                 )) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1066,7 +1066,8 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> { | ||||||
|         | CanonicalType::SyncReset(_) |         | CanonicalType::SyncReset(_) | ||||||
|         | CanonicalType::Reset(_) |         | CanonicalType::Reset(_) | ||||||
|         | CanonicalType::Clock(_) |         | CanonicalType::Clock(_) | ||||||
|         | CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)), |         | CanonicalType::Enum(_) | ||||||
|  |         | CanonicalType::DynSimOnlyValueType(_) => Expr::from_canonical(Expr::canonical(value)), | ||||||
|         CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( |         CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( | ||||||
|             splat_mask(array.element(), value), |             splat_mask(array.element(), value), | ||||||
|             array.len(), |             array.len(), | ||||||
|  |  | ||||||
|  | @ -1524,7 +1524,8 @@ impl TargetState { | ||||||
|                 | CanonicalType::Clock(_) |                 | CanonicalType::Clock(_) | ||||||
|                 | CanonicalType::AsyncReset(_) |                 | CanonicalType::AsyncReset(_) | ||||||
|                 | CanonicalType::SyncReset(_) |                 | CanonicalType::SyncReset(_) | ||||||
|                 | CanonicalType::Reset(_) => TargetStateInner::Single { |                 | CanonicalType::Reset(_) | ||||||
|  |                 | CanonicalType::DynSimOnlyValueType(_) => TargetStateInner::Single { | ||||||
|                     declared_in_block, |                     declared_in_block, | ||||||
|                     written_in_blocks: RefCell::default(), |                     written_in_blocks: RefCell::default(), | ||||||
|                 }, |                 }, | ||||||
|  |  | ||||||
|  | @ -11,11 +11,11 @@ use crate::{ | ||||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, |     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self, |         CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, | ||||||
|  |         StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|         serde_impls::{SerdeCanonicalType, SerdePhantomConst}, |         serde_impls::{SerdeCanonicalType, SerdePhantomConst}, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| use bitvec::slice::BitSlice; |  | ||||||
| use serde::{ | use serde::{ | ||||||
|     Deserialize, Deserializer, Serialize, Serializer, |     Deserialize, Deserializer, Serialize, Serializer, | ||||||
|     de::{DeserializeOwned, Error}, |     de::{DeserializeOwned, Error}, | ||||||
|  | @ -284,19 +284,27 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert!(bits.is_empty()); |         assert!(opaque.is_empty()); | ||||||
|         *self |         *self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert!(bits.is_empty()); |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert!(opaque.is_empty()); | ||||||
|         assert_eq!(*value, *self); |         assert_eq!(*value, *self); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert!(bits.is_empty()); |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|         assert_eq!(*value, *self); |         assert_eq!(*value, *self); | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,9 +5,12 @@ use crate::{ | ||||||
|     expr::{Expr, ToExpr, ops}, |     expr::{Expr, ToExpr, ops}, | ||||||
|     int::{Bool, SInt, UInt}, |     int::{Bool, SInt, UInt}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, |     ty::{ | ||||||
|  |         CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, | ||||||
|  |         OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|  |     }, | ||||||
| }; | }; | ||||||
| use bitvec::slice::BitSlice; | use bitvec::{bits, order::Lsb0}; | ||||||
| 
 | 
 | ||||||
| mod sealed { | mod sealed { | ||||||
|     pub trait ResetTypeSealed {} |     pub trait ResetTypeSealed {} | ||||||
|  | @ -69,19 +72,29 @@ macro_rules! reset_type { | ||||||
|                 retval |                 retval | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|                 assert_eq!(bits.len(), 1); |                 assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|                 bits[0] |                 opaque.bits()[0] | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |             fn sim_value_clone_from_opaque( | ||||||
|                 assert_eq!(bits.len(), 1); |                 &self, | ||||||
|                 *value = bits[0]; |                 value: &mut Self::SimValue, | ||||||
|  |                 opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |             ) { | ||||||
|  |                 assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |                 *value = opaque.bits()[0]; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |             fn sim_value_to_opaque<'w>( | ||||||
|                 assert_eq!(bits.len(), 1); |                 &self, | ||||||
|                 bits.set(0, *value); |                 value: &Self::SimValue, | ||||||
|  |                 writer: OpaqueSimValueWriter<'w>, | ||||||
|  |             ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |                 assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||||
|  |                 writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( | ||||||
|  |                     [bits![0], bits![1]][*value as usize], | ||||||
|  |                 )) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -102,6 +115,7 @@ macro_rules! reset_type { | ||||||
|                 is_storable: false, |                 is_storable: false, | ||||||
|                 is_castable_from_bits: $is_castable_from_bits, |                 is_castable_from_bits: $is_castable_from_bits, | ||||||
|                 bit_width: 1, |                 bit_width: 1, | ||||||
|  |                 sim_only_values_len: 0, | ||||||
|             }; |             }; | ||||||
|             const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; |             const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ use crate::{ | ||||||
|             TypeLen, |             TypeLen, | ||||||
|         }, |         }, | ||||||
|         time::{SimDuration, SimInstant}, |         time::{SimDuration, SimInstant}, | ||||||
|         value::SimValue, |         value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue}, | ||||||
|     }, |     }, | ||||||
|     util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, |     util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, | ||||||
| }; | }; | ||||||
|  | @ -503,6 +503,11 @@ pub trait TraceWriter: fmt::Debug + 'static { | ||||||
|         variant_index: usize, |         variant_index: usize, | ||||||
|         ty: Enum, |         ty: Enum, | ||||||
|     ) -> Result<(), Self::Error>; |     ) -> Result<(), Self::Error>; | ||||||
|  |     fn set_signal_sim_only_value( | ||||||
|  |         &mut self, | ||||||
|  |         id: TraceScalarId, | ||||||
|  |         value: &DynSimOnlyValue, | ||||||
|  |     ) -> Result<(), Self::Error>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>); | pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>); | ||||||
|  | @ -557,6 +562,11 @@ trait TraceWriterDynTrait: fmt::Debug + 'static { | ||||||
|         variant_index: usize, |         variant_index: usize, | ||||||
|         ty: Enum, |         ty: Enum, | ||||||
|     ) -> std::io::Result<()>; |     ) -> std::io::Result<()>; | ||||||
|  |     fn set_signal_sim_only_value_dyn( | ||||||
|  |         &mut self, | ||||||
|  |         id: TraceScalarId, | ||||||
|  |         value: &DynSimOnlyValue, | ||||||
|  |     ) -> std::io::Result<()>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: TraceWriter> TraceWriterDynTrait for T { | impl<T: TraceWriter> TraceWriterDynTrait for T { | ||||||
|  | @ -616,6 +626,13 @@ impl<T: TraceWriter> TraceWriterDynTrait for T { | ||||||
|                 .map_err(err_into_io)?, |                 .map_err(err_into_io)?, | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |     fn set_signal_sim_only_value_dyn( | ||||||
|  |         &mut self, | ||||||
|  |         id: TraceScalarId, | ||||||
|  |         value: &DynSimOnlyValue, | ||||||
|  |     ) -> std::io::Result<()> { | ||||||
|  |         Ok(TraceWriter::set_signal_sim_only_value(self, id, value).map_err(err_into_io)?) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>); | pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>); | ||||||
|  | @ -680,6 +697,13 @@ impl TraceWriter for DynTraceWriter { | ||||||
|         self.0 |         self.0 | ||||||
|             .set_signal_enum_discriminant_dyn(id, variant_index, ty) |             .set_signal_enum_discriminant_dyn(id, variant_index, ty) | ||||||
|     } |     } | ||||||
|  |     fn set_signal_sim_only_value( | ||||||
|  |         &mut self, | ||||||
|  |         id: TraceScalarId, | ||||||
|  |         value: &DynSimOnlyValue, | ||||||
|  |     ) -> Result<(), Self::Error> { | ||||||
|  |         self.0.set_signal_sim_only_value_dyn(id, value) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
|  | @ -844,6 +868,10 @@ pub(crate) enum SimTraceKind { | ||||||
|         index: StatePartIndex<StatePartKindSmallSlots>, |         index: StatePartIndex<StatePartKindSmallSlots>, | ||||||
|         ty: Enum, |         ty: Enum, | ||||||
|     }, |     }, | ||||||
|  |     SimOnlyValue { | ||||||
|  |         index: StatePartIndex<StatePartKindSmallSlots>, | ||||||
|  |         ty: DynSimOnlyValueType, | ||||||
|  |     }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl SimTraceKind { | impl SimTraceKind { | ||||||
|  | @ -866,6 +894,10 @@ impl SimTraceKind { | ||||||
|             SimTraceKind::EnumDiscriminant { index: _, ty } => { |             SimTraceKind::EnumDiscriminant { index: _, ty } => { | ||||||
|                 BitVec::repeat(false, ty.discriminant_bit_width()) |                 BitVec::repeat(false, ty.discriminant_bit_width()) | ||||||
|             } |             } | ||||||
|  |             SimTraceKind::SimOnlyValue { index: _, ty: _ } => { | ||||||
|  |                 // use all ones as the default initializer to help catch uninitialized indexes
 | ||||||
|  |                 BitVec::repeat(true, SmallUInt::BITS as usize) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1416,6 +1448,8 @@ struct SimulationImpl { | ||||||
|     clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>, |     clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>, | ||||||
|     breakpoints: Option<BreakpointsSet>, |     breakpoints: Option<BreakpointsSet>, | ||||||
|     generator_waker: std::task::Waker, |     generator_waker: std::task::Waker, | ||||||
|  |     sim_only_values: Vec<Option<DynSimOnlyValue>>, | ||||||
|  |     free_sim_only_value_indexes: Vec<usize>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl fmt::Debug for SimulationImpl { | impl fmt::Debug for SimulationImpl { | ||||||
|  | @ -1440,6 +1474,8 @@ impl SimulationImpl { | ||||||
|             clocks_triggered, |             clocks_triggered, | ||||||
|             breakpoints: _, |             breakpoints: _, | ||||||
|             generator_waker: _, |             generator_waker: _, | ||||||
|  |             sim_only_values, | ||||||
|  |             free_sim_only_value_indexes, | ||||||
|         } = self; |         } = self; | ||||||
|         f.debug_struct("Simulation") |         f.debug_struct("Simulation") | ||||||
|             .field("state", state) |             .field("state", state) | ||||||
|  | @ -1453,6 +1489,8 @@ impl SimulationImpl { | ||||||
|             .field("trace_writers", trace_writers) |             .field("trace_writers", trace_writers) | ||||||
|             .field("instant", instant) |             .field("instant", instant) | ||||||
|             .field("clocks_triggered", clocks_triggered) |             .field("clocks_triggered", clocks_triggered) | ||||||
|  |             .field("sim_only_values", &SliceAsMapDebug(sim_only_values)) | ||||||
|  |             .field("free_sim_only_value_indexes", free_sim_only_value_indexes) | ||||||
|             .finish_non_exhaustive() |             .finish_non_exhaustive() | ||||||
|     } |     } | ||||||
|     fn new(compiled: Compiled<Bundle>) -> Self { |     fn new(compiled: Compiled<Bundle>) -> Self { | ||||||
|  | @ -1516,6 +1554,8 @@ impl SimulationImpl { | ||||||
|             clocks_triggered: compiled.clocks_triggered, |             clocks_triggered: compiled.clocks_triggered, | ||||||
|             breakpoints: None, |             breakpoints: None, | ||||||
|             generator_waker: Arc::new(GeneratorWaker).into(), |             generator_waker: Arc::new(GeneratorWaker).into(), | ||||||
|  |             sim_only_values: vec![], | ||||||
|  |             free_sim_only_value_indexes: vec![], | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn write_traces<const ONLY_IF_CHANGED: bool>( |     fn write_traces<const ONLY_IF_CHANGED: bool>( | ||||||
|  | @ -1586,6 +1626,18 @@ impl SimulationImpl { | ||||||
|                         ty, |                         ty, | ||||||
|                     )?; |                     )?; | ||||||
|                 } |                 } | ||||||
|  |                 SimTraceKind::SimOnlyValue { .. } => { | ||||||
|  |                     let mut sim_only_value_index = [0; mem::size_of::<SmallUInt>()]; | ||||||
|  |                     sim_only_value_index.view_bits_mut::<Lsb0>()[0..state.len()] | ||||||
|  |                         .clone_from_bitslice(state); | ||||||
|  |                     let sim_only_value_index = SmallUInt::from_le_bytes(sim_only_value_index); | ||||||
|  |                     trace_writer.set_signal_sim_only_value( | ||||||
|  |                         id, | ||||||
|  |                         self.sim_only_values[sim_only_value_index as usize] | ||||||
|  |                             .as_ref() | ||||||
|  |                             .expect("should be Some"), | ||||||
|  |                     )?; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Ok(trace_writer) |         Ok(trace_writer) | ||||||
|  | @ -1635,7 +1687,8 @@ impl SimulationImpl { | ||||||
|                 } |                 } | ||||||
|                 SimTraceKind::SmallUInt { index, ty: _ } |                 SimTraceKind::SmallUInt { index, ty: _ } | ||||||
|                 | SimTraceKind::SmallSInt { index, ty: _ } |                 | SimTraceKind::SmallSInt { index, ty: _ } | ||||||
|                 | SimTraceKind::EnumDiscriminant { index, ty: _ } => { |                 | SimTraceKind::EnumDiscriminant { index, ty: _ } | ||||||
|  |                 | SimTraceKind::SimOnlyValue { index, ty: _ } => { | ||||||
|                     let bytes = self.state.small_slots[index].to_le_bytes(); |                     let bytes = self.state.small_slots[index].to_le_bytes(); | ||||||
|                     let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); |                     let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); | ||||||
|                     let bitslice = &bitslice[..state.len()]; |                     let bitslice = &bitslice[..state.len()]; | ||||||
|  | @ -2050,6 +2103,7 @@ impl SimulationImpl { | ||||||
|                     CanonicalType::Reset(_) => false, |                     CanonicalType::Reset(_) => false, | ||||||
|                     CanonicalType::Clock(_) => false, |                     CanonicalType::Clock(_) => false, | ||||||
|                     CanonicalType::PhantomConst(_) => unreachable!(), |                     CanonicalType::PhantomConst(_) => unreachable!(), | ||||||
|  |                     CanonicalType::DynSimOnlyValueType(_) => false, | ||||||
|                 }; |                 }; | ||||||
|                 let bit_indexes = |                 let bit_indexes = | ||||||
|                     start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); |                     start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); | ||||||
|  | @ -2409,6 +2463,21 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SortedMapDebug<'_, K, V> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | struct SliceAsMapDebug<'a, T>(&'a [Option<T>]); | ||||||
|  | 
 | ||||||
|  | impl<T: fmt::Debug> fmt::Debug for SliceAsMapDebug<'_, T> { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         f.debug_map() | ||||||
|  |             .entries( | ||||||
|  |                 self.0 | ||||||
|  |                     .iter() | ||||||
|  |                     .enumerate() | ||||||
|  |                     .filter_map(|(k, v)| Some((k, v.as_ref()?))), | ||||||
|  |             ) | ||||||
|  |             .finish() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<T: BundleType> fmt::Debug for Simulation<T> { | impl<T: BundleType> fmt::Debug for Simulation<T> { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|         let Self { sim_impl, io } = self; |         let Self { sim_impl, io } = self; | ||||||
|  |  | ||||||
|  | @ -9,60 +9,82 @@ 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, StaticType, Type}, |     source_location::SourceLocation, | ||||||
|  |     ty::{ | ||||||
|  |         CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice, | ||||||
|  |         OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self, | ||||||
|  |     }, | ||||||
|     util::{ |     util::{ | ||||||
|         ConstUsize, |         ConstUsize, HashMap, | ||||||
|         alternating_cell::{AlternatingCell, AlternatingCellMethods}, |         alternating_cell::{AlternatingCell, AlternatingCellMethods}, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| use bitvec::{slice::BitSlice, vec::BitVec}; | use bitvec::{slice::BitSlice, vec::BitVec}; | ||||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | use hashbrown::hash_map::Entry; | ||||||
|  | use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _}; | ||||||
| use std::{ | use std::{ | ||||||
|     fmt, |     borrow::Cow, | ||||||
|  |     fmt::{self, Write}, | ||||||
|  |     hash::{BuildHasher, Hash, Hasher, RandomState}, | ||||||
|     ops::{Deref, DerefMut}, |     ops::{Deref, DerefMut}, | ||||||
|     sync::Arc, |     sync::{Arc, Mutex}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pub(crate) mod sim_only_value_unsafe; | ||||||
|  | 
 | ||||||
|  | pub use sim_only_value_unsafe::{ | ||||||
|  |     DynSimOnlyValue, DynSimOnlyValueType, SimOnlyValue, SimOnlyValueTrait, SimOnlyValueType, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Copy, Clone, Eq, PartialEq)] | #[derive(Copy, Clone, Eq, PartialEq)] | ||||||
| enum ValidFlags { | enum ValidFlags { | ||||||
|     BothValid = 0, |     BothValid = 0, | ||||||
|     OnlyValueValid = 1, |     OnlyValueValid = 1, | ||||||
|     OnlyBitsValid = 2, |     OnlyOpaqueValid = 2, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| struct SimValueInner<T: Type> { | struct SimValueInner<T: Type> { | ||||||
|     value: T::SimValue, |     value: T::SimValue, | ||||||
|     bits: UIntValue, |     opaque: OpaqueSimValue, | ||||||
|     valid_flags: ValidFlags, |     valid_flags: ValidFlags, | ||||||
|     ty: T, |     ty: T, | ||||||
|  |     sim_only_values_len: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T: Type> SimValueInner<T> { | impl<T: Type> SimValueInner<T> { | ||||||
|     fn fill_bits(&mut self) { |     fn size(&self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.opaque.bit_width(), | ||||||
|  |             sim_only_values_len: self.sim_only_values_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn fill_opaque(&mut self) { | ||||||
|         match self.valid_flags { |         match self.valid_flags { | ||||||
|             ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {} |             ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {} | ||||||
|             ValidFlags::OnlyValueValid => { |             ValidFlags::OnlyValueValid => { | ||||||
|                 self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()); |                 OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| { | ||||||
|  |                     self.ty.sim_value_to_opaque(&self.value, writer) | ||||||
|  |                 }); | ||||||
|                 self.valid_flags = ValidFlags::BothValid; |                 self.valid_flags = ValidFlags::BothValid; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn into_bits(mut self) -> UIntValue { |     fn into_opaque(mut self) -> OpaqueSimValue { | ||||||
|         self.fill_bits(); |         self.fill_opaque(); | ||||||
|         self.bits |         self.opaque | ||||||
|     } |     } | ||||||
|     fn bits_mut(&mut self) -> &mut UIntValue { |     fn opaque_mut(&mut self) -> &mut OpaqueSimValue { | ||||||
|         self.fill_bits(); |         self.fill_opaque(); | ||||||
|         self.valid_flags = ValidFlags::OnlyBitsValid; |         self.valid_flags = ValidFlags::OnlyOpaqueValid; | ||||||
|         &mut self.bits |         &mut self.opaque | ||||||
|     } |     } | ||||||
|     fn fill_value(&mut self) { |     fn fill_value(&mut self) { | ||||||
|         match self.valid_flags { |         match self.valid_flags { | ||||||
|             ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} |             ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} | ||||||
|             ValidFlags::OnlyBitsValid => { |             ValidFlags::OnlyOpaqueValid => { | ||||||
|                 self.ty |                 self.ty | ||||||
|                     .sim_value_clone_from_bits(&mut self.value, self.bits.bits()); |                     .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()); | ||||||
|                 self.valid_flags = ValidFlags::BothValid; |                 self.valid_flags = ValidFlags::BothValid; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -83,11 +105,13 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> { | ||||||
|         match self.valid_flags { |         match self.valid_flags { | ||||||
|             ValidFlags::BothValid => return, |             ValidFlags::BothValid => return, | ||||||
|             ValidFlags::OnlyValueValid => { |             ValidFlags::OnlyValueValid => { | ||||||
|                 self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()) |                 OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| { | ||||||
|  |                     self.ty.sim_value_to_opaque(&self.value, writer) | ||||||
|  |                 }) | ||||||
|             } |             } | ||||||
|             ValidFlags::OnlyBitsValid => self |             ValidFlags::OnlyOpaqueValid => self | ||||||
|                 .ty |                 .ty | ||||||
|                 .sim_value_clone_from_bits(&mut self.value, self.bits.bits()), |                 .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()), | ||||||
|         } |         } | ||||||
|         self.valid_flags = ValidFlags::BothValid; |         self.valid_flags = ValidFlags::BothValid; | ||||||
|     } |     } | ||||||
|  | @ -143,13 +167,15 @@ impl<T: Type + Clone> Clone for SimValue<T> { | ||||||
| 
 | 
 | ||||||
| impl<T: Type> SimValue<T> { | impl<T: Type> SimValue<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_bits(ty: T, bits: UIntValue) -> Self { |     pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self { | ||||||
|         assert_eq!(ty.canonical().bit_width(), bits.width()); |         let size = ty.canonical().size(); | ||||||
|  |         assert_eq!(size, opaque.size()); | ||||||
|         let inner = SimValueInner { |         let inner = SimValueInner { | ||||||
|             value: ty.sim_value_from_bits(bits.bits()), |             value: ty.sim_value_from_opaque(opaque.as_slice()), | ||||||
|             bits, |             opaque, | ||||||
|             valid_flags: ValidFlags::BothValid, |             valid_flags: ValidFlags::BothValid, | ||||||
|             ty, |             ty, | ||||||
|  |             sim_only_values_len: size.sim_only_values_len, | ||||||
|         }; |         }; | ||||||
|         Self { |         Self { | ||||||
|             inner: AlternatingCell::new_shared(inner), |             inner: AlternatingCell::new_shared(inner), | ||||||
|  | @ -157,14 +183,30 @@ impl<T: Type> SimValue<T> { | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { |     pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { | ||||||
|         Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec()))) |         Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new()) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     pub fn from_bitslice_and_sim_only_values( | ||||||
|  |         ty: T, | ||||||
|  |         bits: &BitSlice, | ||||||
|  |         sim_only_values: Vec<DynSimOnlyValue>, | ||||||
|  |     ) -> Self { | ||||||
|  |         Self::from_opaque( | ||||||
|  |             ty, | ||||||
|  |             OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values), | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
|     pub fn from_value(ty: T, value: T::SimValue) -> Self { |     pub fn from_value(ty: T, value: T::SimValue) -> Self { | ||||||
|  |         let type_properties = ty.canonical().type_properties(); | ||||||
|         let inner = SimValueInner { |         let inner = SimValueInner { | ||||||
|             bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))), |             opaque: OpaqueSimValue::from_bits_and_sim_only_values( | ||||||
|  |                 UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))), | ||||||
|  |                 Vec::with_capacity(type_properties.sim_only_values_len), | ||||||
|  |             ), | ||||||
|             value, |             value, | ||||||
|             valid_flags: ValidFlags::OnlyValueValid, |             valid_flags: ValidFlags::OnlyValueValid, | ||||||
|             ty, |             ty, | ||||||
|  |             sim_only_values_len: type_properties.sim_only_values_len, | ||||||
|         }; |         }; | ||||||
|         Self { |         Self { | ||||||
|             inner: AlternatingCell::new_unique(inner), |             inner: AlternatingCell::new_unique(inner), | ||||||
|  | @ -173,18 +215,24 @@ impl<T: Type> SimValue<T> { | ||||||
|     pub fn ty(this: &Self) -> T { |     pub fn ty(this: &Self) -> T { | ||||||
|         this.inner.share().ty |         this.inner.share().ty | ||||||
|     } |     } | ||||||
|     pub fn into_bits(this: Self) -> UIntValue { |     pub fn into_opaque(this: Self) -> OpaqueSimValue { | ||||||
|         this.inner.into_inner().into_bits() |         this.inner.into_inner().into_opaque() | ||||||
|     } |     } | ||||||
|     pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) { |     pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) { | ||||||
|         let inner = this.inner.into_inner(); |         let inner = this.inner.into_inner(); | ||||||
|         (inner.ty, inner.into_bits()) |         (inner.ty, inner.into_opaque()) | ||||||
|  |     } | ||||||
|  |     pub fn opaque(this: &Self) -> &OpaqueSimValue { | ||||||
|  |         &this.inner.share().opaque | ||||||
|  |     } | ||||||
|  |     pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue { | ||||||
|  |         &mut this.inner.unique().opaque | ||||||
|     } |     } | ||||||
|     pub fn bits(this: &Self) -> &UIntValue { |     pub fn bits(this: &Self) -> &UIntValue { | ||||||
|         &this.inner.share().bits |         Self::opaque(this).bits() | ||||||
|     } |     } | ||||||
|     pub fn bits_mut(this: &mut Self) -> &mut UIntValue { |     pub fn bits_mut(this: &mut Self) -> &mut UIntValue { | ||||||
|         this.inner.unique().bits_mut() |         Self::opaque_mut(this).bits_mut() | ||||||
|     } |     } | ||||||
|     pub fn into_value(this: Self) -> T::SimValue { |     pub fn into_value(this: Self) -> T::SimValue { | ||||||
|         this.inner.into_inner().into_value() |         this.inner.into_inner().into_value() | ||||||
|  | @ -197,59 +245,59 @@ impl<T: Type> SimValue<T> { | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_canonical(v: SimValue<CanonicalType>) -> Self { |     pub fn from_canonical(v: SimValue<CanonicalType>) -> Self { | ||||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); |         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||||
|         Self::from_bits(T::from_canonical(ty), bits) |         Self::from_opaque(T::from_canonical(ty), opaque) | ||||||
|     } |     } | ||||||
|     pub fn into_canonical(this: Self) -> SimValue<CanonicalType> { |     pub fn into_canonical(this: Self) -> SimValue<CanonicalType> { | ||||||
|         let (ty, bits) = Self::into_ty_and_bits(this); |         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||||
|         SimValue::from_bits(ty.canonical(), bits) |         SimValue::from_opaque(ty.canonical(), opaque) | ||||||
|     } |     } | ||||||
|     pub fn canonical(this: &Self) -> SimValue<CanonicalType> { |     pub fn canonical(this: &Self) -> SimValue<CanonicalType> { | ||||||
|         SimValue::from_bits(Self::ty(this).canonical(), Self::bits(this).clone()) |         SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone()) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self |     pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self | ||||||
|     where |     where | ||||||
|         T: IntType, |         T: IntType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); |         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||||
|         SimValue::from_bits(T::from_dyn_int(ty), bits) |         SimValue::from_opaque(T::from_dyn_int(ty), opaque) | ||||||
|     } |     } | ||||||
|     pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn> |     pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn> | ||||||
|     where |     where | ||||||
|         T: IntType, |         T: IntType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = Self::into_ty_and_bits(this); |         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||||
|         SimValue::from_bits(ty.as_dyn_int(), bits) |         SimValue::from_opaque(ty.as_dyn_int(), opaque) | ||||||
|     } |     } | ||||||
|     pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn> |     pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn> | ||||||
|     where |     where | ||||||
|         T: IntType, |         T: IntType, | ||||||
|     { |     { | ||||||
|         SimValue::from_bits(Self::ty(this).as_dyn_int(), Self::bits(&this).clone()) |         SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone()) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     pub fn from_bundle(v: SimValue<Bundle>) -> Self |     pub fn from_bundle(v: SimValue<Bundle>) -> Self | ||||||
|     where |     where | ||||||
|         T: BundleType, |         T: BundleType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); |         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||||
|         SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits) |         SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque) | ||||||
|     } |     } | ||||||
|     pub fn into_bundle(this: Self) -> SimValue<Bundle> |     pub fn into_bundle(this: Self) -> SimValue<Bundle> | ||||||
|     where |     where | ||||||
|         T: BundleType, |         T: BundleType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = Self::into_ty_and_bits(this); |         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||||
|         SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits) |         SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque) | ||||||
|     } |     } | ||||||
|     pub fn to_bundle(this: &Self) -> SimValue<Bundle> |     pub fn to_bundle(this: &Self) -> SimValue<Bundle> | ||||||
|     where |     where | ||||||
|         T: BundleType, |         T: BundleType, | ||||||
|     { |     { | ||||||
|         SimValue::from_bits( |         SimValue::from_opaque( | ||||||
|             Bundle::from_canonical(Self::ty(this).canonical()), |             Bundle::from_canonical(Self::ty(this).canonical()), | ||||||
|             Self::bits(&this).clone(), |             Self::opaque(&this).clone(), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|  | @ -257,23 +305,23 @@ impl<T: Type> SimValue<T> { | ||||||
|     where |     where | ||||||
|         T: EnumType, |         T: EnumType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); |         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||||
|         SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits) |         SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque) | ||||||
|     } |     } | ||||||
|     pub fn into_enum(this: Self) -> SimValue<Enum> |     pub fn into_enum(this: Self) -> SimValue<Enum> | ||||||
|     where |     where | ||||||
|         T: EnumType, |         T: EnumType, | ||||||
|     { |     { | ||||||
|         let (ty, bits) = Self::into_ty_and_bits(this); |         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||||
|         SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits) |         SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque) | ||||||
|     } |     } | ||||||
|     pub fn to_enum(this: &Self) -> SimValue<Enum> |     pub fn to_enum(this: &Self) -> SimValue<Enum> | ||||||
|     where |     where | ||||||
|         T: EnumType, |         T: EnumType, | ||||||
|     { |     { | ||||||
|         SimValue::from_bits( |         SimValue::from_opaque( | ||||||
|             Enum::from_canonical(Self::ty(this).canonical()), |             Enum::from_canonical(Self::ty(this).canonical()), | ||||||
|             Self::bits(&this).clone(), |             Self::opaque(&this).clone(), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -308,7 +356,11 @@ impl<T: Type> ToExpr for SimValue<T> { | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn to_expr(&self) -> Expr<Self::Type> { |     fn to_expr(&self) -> Expr<Self::Type> { | ||||||
|         let inner = self.inner.share(); |         let inner = self.inner.share(); | ||||||
|         inner.bits.cast_bits_to(inner.ty) |         assert_eq!( | ||||||
|  |             inner.sim_only_values_len, 0, | ||||||
|  |             "can't convert sim-only values to Expr" | ||||||
|  |         ); | ||||||
|  |         inner.opaque.bits().cast_bits_to(inner.ty) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -443,12 +495,15 @@ impl<T: Type> ToSimValueWithType<T> for BitVec { | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_into_sim_value_with_type(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_opaque(ty, OpaqueSimValue::from_bits(UIntValue::new_dyn(self))) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[track_caller] |     #[track_caller] | ||||||
|     fn arc_to_sim_value_with_type(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_opaque( | ||||||
|  |             ty, | ||||||
|  |             OpaqueSimValue::from_bits(UIntValue::new_dyn(self.clone())), | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -792,16 +847,18 @@ impl ToSimValueWithType<CanonicalType> for bool { | ||||||
|             | CanonicalType::Array(_) |             | CanonicalType::Array(_) | ||||||
|             | CanonicalType::Enum(_) |             | CanonicalType::Enum(_) | ||||||
|             | CanonicalType::Bundle(_) |             | CanonicalType::Bundle(_) | ||||||
|             | CanonicalType::PhantomConst(_) => { |             | CanonicalType::PhantomConst(_) | ||||||
|  |             | CanonicalType::DynSimOnlyValueType(_) => { | ||||||
|                 panic!("can't create SimValue from bool: expected value of type: {ty:?}"); |                 panic!("can't create SimValue from bool: expected value of type: {ty:?}"); | ||||||
|             } |             } | ||||||
|             CanonicalType::Bool(_) |             CanonicalType::Bool(_) | ||||||
|             | CanonicalType::AsyncReset(_) |             | CanonicalType::AsyncReset(_) | ||||||
|             | CanonicalType::SyncReset(_) |             | CanonicalType::SyncReset(_) | ||||||
|             | CanonicalType::Reset(_) |             | CanonicalType::Reset(_) | ||||||
|             | CanonicalType::Clock(_) => { |             | CanonicalType::Clock(_) => SimValue::from_opaque( | ||||||
|                 SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))) |                 ty, | ||||||
|             } |                 OpaqueSimValue::from_bits(UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))), | ||||||
|  |             ), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -911,3 +968,330 @@ macro_rules! impl_to_sim_value_for_int_value { | ||||||
| 
 | 
 | ||||||
| impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); | impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); | ||||||
| impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); | impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); | ||||||
|  | 
 | ||||||
|  | #[derive(Default)] | ||||||
|  | struct DynSimOnlyValueTypeSerdeTableRest { | ||||||
|  |     from_serde: HashMap<DynSimOnlyValueTypeSerdeId, DynSimOnlyValueType>, | ||||||
|  |     serde_id_random_state: RandomState, | ||||||
|  |     buffer: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValueTypeSerdeTableRest { | ||||||
|  |     #[cold] | ||||||
|  |     fn add_new(&mut self, ty: DynSimOnlyValueType) -> DynSimOnlyValueTypeSerdeId { | ||||||
|  |         let mut try_number = 0u64; | ||||||
|  |         let mut hasher = self.serde_id_random_state.build_hasher(); | ||||||
|  |         // extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
 | ||||||
|  |         write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail"); | ||||||
|  |         self.buffer.hash(&mut hasher); | ||||||
|  |         loop { | ||||||
|  |             let mut hasher = hasher.clone(); | ||||||
|  |             try_number.hash(&mut hasher); | ||||||
|  |             try_number += 1; | ||||||
|  |             let retval = DynSimOnlyValueTypeSerdeId(std::array::from_fn(|i| { | ||||||
|  |                 let mut hasher = hasher.clone(); | ||||||
|  |                 i.hash(&mut hasher); | ||||||
|  |                 hasher.finish() as u32 | ||||||
|  |             })); | ||||||
|  |             match self.from_serde.entry(retval) { | ||||||
|  |                 Entry::Occupied(_) => continue, | ||||||
|  |                 Entry::Vacant(e) => { | ||||||
|  |                     e.insert(ty); | ||||||
|  |                     return retval; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Default)] | ||||||
|  | struct DynSimOnlyValueTypeSerdeTable { | ||||||
|  |     to_serde: HashMap<DynSimOnlyValueType, DynSimOnlyValueTypeSerdeId>, | ||||||
|  |     rest: DynSimOnlyValueTypeSerdeTableRest, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlyValueTypeSerdeTable>> = | ||||||
|  |     Mutex::new(None); | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] | ||||||
|  | #[serde(transparent)] | ||||||
|  | struct DynSimOnlyValueTypeSerdeId([u32; 4]); | ||||||
|  | 
 | ||||||
|  | impl From<DynSimOnlyValueType> for DynSimOnlyValueTypeSerdeId { | ||||||
|  |     fn from(ty: DynSimOnlyValueType) -> Self { | ||||||
|  |         let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE | ||||||
|  |             .lock() | ||||||
|  |             .expect("shouldn't be poison"); | ||||||
|  |         let DynSimOnlyValueTypeSerdeTable { to_serde, rest } = locked.get_or_insert_default(); | ||||||
|  |         match to_serde.entry(ty) { | ||||||
|  |             Entry::Occupied(occupied_entry) => *occupied_entry.get(), | ||||||
|  |             Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValueTypeSerdeId { | ||||||
|  |     fn ty(self) -> Option<DynSimOnlyValueType> { | ||||||
|  |         let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE | ||||||
|  |             .lock() | ||||||
|  |             .expect("shouldn't be poison"); | ||||||
|  |         Some(*locked.as_ref()?.rest.from_serde.get(&self)?) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] | ||||||
|  | struct DynSimOnlyValueTypeSerde<'a> { | ||||||
|  |     random_id: DynSimOnlyValueTypeSerdeId, | ||||||
|  |     #[serde(borrow)] | ||||||
|  |     type_name: Cow<'a, str>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Serialize for DynSimOnlyValueType { | ||||||
|  |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||||
|  |     where | ||||||
|  |         S: Serializer, | ||||||
|  |     { | ||||||
|  |         DynSimOnlyValueTypeSerde { | ||||||
|  |             random_id: (*self).into(), | ||||||
|  |             type_name: Cow::Borrowed(self.type_name()), | ||||||
|  |         } | ||||||
|  |         .serialize(serializer) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'de> Deserialize<'de> for DynSimOnlyValueType { | ||||||
|  |     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||||
|  |     where | ||||||
|  |         D: Deserializer<'de>, | ||||||
|  |     { | ||||||
|  |         let deserialized = DynSimOnlyValueTypeSerde::deserialize(deserializer)?; | ||||||
|  |         let retval = deserialized | ||||||
|  |             .random_id | ||||||
|  |             .ty() | ||||||
|  |             .filter(|ty| ty.type_name() == deserialized.type_name); | ||||||
|  |         retval.ok_or_else(|| D::Error::custom("doesn't match any DynSimOnlyValueType that was serialized this time this program was run")) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValueType { | ||||||
|  |     pub const fn type_properties(self) -> TypeProperties { | ||||||
|  |         TypeProperties { | ||||||
|  |             is_passive: true, | ||||||
|  |             is_storable: true, | ||||||
|  |             is_castable_from_bits: false, | ||||||
|  |             bit_width: 0, | ||||||
|  |             sim_only_values_len: 1, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn can_connect(self, other: Self) -> bool { | ||||||
|  |         self == other | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Type for DynSimOnlyValueType { | ||||||
|  |     type BaseType = DynSimOnlyValueType; | ||||||
|  |     type MaskType = Bool; | ||||||
|  |     type SimValue = DynSimOnlyValue; | ||||||
|  | 
 | ||||||
|  |     impl_match_variant_as_self!(); | ||||||
|  | 
 | ||||||
|  |     fn mask_type(&self) -> Self::MaskType { | ||||||
|  |         Bool | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn canonical(&self) -> CanonicalType { | ||||||
|  |         CanonicalType::DynSimOnlyValueType(*self) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn from_canonical(canonical_type: CanonicalType) -> Self { | ||||||
|  |         let CanonicalType::DynSimOnlyValueType(v) = canonical_type else { | ||||||
|  |             panic!("expected DynSimOnlyValueType"); | ||||||
|  |         }; | ||||||
|  |         v | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn source_location() -> SourceLocation { | ||||||
|  |         SourceLocation::builtin() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|  |         assert_eq!(opaque.size(), self.type_properties().size()); | ||||||
|  |         opaque.sim_only_values()[0].clone() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_clone_from_opaque( | ||||||
|  |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(opaque.size(), self.type_properties().size()); | ||||||
|  |         value.clone_from(&opaque.sim_only_values()[0]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_to_opaque<'w>( | ||||||
|  |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> crate::ty::OpaqueSimValueWritten<'w> { | ||||||
|  |         writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts( | ||||||
|  |             BitSlice::empty(), | ||||||
|  |             std::array::from_ref(value), | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> Type for SimOnlyValueType<T> { | ||||||
|  |     type BaseType = DynSimOnlyValueType; | ||||||
|  |     type MaskType = Bool; | ||||||
|  |     type SimValue = SimOnlyValue<T>; | ||||||
|  | 
 | ||||||
|  |     impl_match_variant_as_self!(); | ||||||
|  | 
 | ||||||
|  |     fn mask_type(&self) -> Self::MaskType { | ||||||
|  |         Bool | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn canonical(&self) -> CanonicalType { | ||||||
|  |         DynSimOnlyValueType::from(*self).canonical() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn from_canonical(canonical_type: CanonicalType) -> Self { | ||||||
|  |         DynSimOnlyValueType::from_canonical(canonical_type) | ||||||
|  |             .downcast() | ||||||
|  |             .expect("got wrong SimOnlyValueType") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn source_location() -> SourceLocation { | ||||||
|  |         SourceLocation::builtin() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|  |         assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size()); | ||||||
|  |         SimOnlyValue::new( | ||||||
|  |             opaque.sim_only_values()[0] | ||||||
|  |                 .downcast_ref::<T>() | ||||||
|  |                 .expect("type mismatch") | ||||||
|  |                 .clone(), | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_clone_from_opaque( | ||||||
|  |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size()); | ||||||
|  |         (**value).clone_from( | ||||||
|  |             &opaque.sim_only_values()[0] | ||||||
|  |                 .downcast_ref::<T>() | ||||||
|  |                 .expect("type mismatch"), | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn sim_value_to_opaque<'w>( | ||||||
|  |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> crate::ty::OpaqueSimValueWritten<'w> { | ||||||
|  |         SimOnlyValue::with_dyn_ref(value, |value| { | ||||||
|  |             writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts( | ||||||
|  |                 BitSlice::empty(), | ||||||
|  |                 std::array::from_ref(value), | ||||||
|  |             )) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> StaticType for SimOnlyValueType<T> { | ||||||
|  |     const TYPE: Self = Self::new(); | ||||||
|  | 
 | ||||||
|  |     const MASK_TYPE: Self::MaskType = Bool; | ||||||
|  | 
 | ||||||
|  |     const TYPE_PROPERTIES: TypeProperties = DynSimOnlyValueType::of::<T>().type_properties(); | ||||||
|  | 
 | ||||||
|  |     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> fmt::Debug for SimOnlyValue<T> { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         Self::with_dyn_ref(self, |this| fmt::Debug::fmt(this, f)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Serialize, Deserialize)] | ||||||
|  | #[serde(rename = "SimOnlyValue")] | ||||||
|  | struct SerdeSimOnlyValue<'a> { | ||||||
|  |     ty: DynSimOnlyValueType, | ||||||
|  |     #[serde(borrow)] | ||||||
|  |     value: Cow<'a, str>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Serialize for DynSimOnlyValue { | ||||||
|  |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||||
|  |     where | ||||||
|  |         S: Serializer, | ||||||
|  |     { | ||||||
|  |         SerdeSimOnlyValue { | ||||||
|  |             ty: self.ty(), | ||||||
|  |             value: Cow::Owned(self.serialize_to_json_string().map_err(S::Error::custom)?), | ||||||
|  |         } | ||||||
|  |         .serialize(serializer) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'de> Deserialize<'de> for DynSimOnlyValue { | ||||||
|  |     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||||
|  |     where | ||||||
|  |         D: Deserializer<'de>, | ||||||
|  |     { | ||||||
|  |         let SerdeSimOnlyValue { ty, value } = Deserialize::deserialize(deserializer)?; | ||||||
|  |         ty.deserialize_from_json_string(&value) | ||||||
|  |             .map_err(D::Error::custom) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToSimValueWithType<DynSimOnlyValueType> for DynSimOnlyValue { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value_with_type(&self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> { | ||||||
|  |         assert_eq!(self.ty(), ty, "mismatched type"); | ||||||
|  |         SimValue::from_value(ty, self.clone()) | ||||||
|  |     } | ||||||
|  |     #[track_caller] | ||||||
|  |     fn into_sim_value_with_type(self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> { | ||||||
|  |         assert_eq!(self.ty(), ty, "mismatched type"); | ||||||
|  |         SimValue::from_value(ty, self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> ToSimValueWithType<SimOnlyValueType<T>> for SimOnlyValue<T> { | ||||||
|  |     fn to_sim_value_with_type(&self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> { | ||||||
|  |         SimValue::from_value(ty, self.clone()) | ||||||
|  |     } | ||||||
|  |     fn into_sim_value_with_type(self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> { | ||||||
|  |         SimValue::from_value(ty, self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToSimValue for DynSimOnlyValue { | ||||||
|  |     type Type = DynSimOnlyValueType; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(self.ty(), self.clone()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(self.ty(), self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> { | ||||||
|  |     type Type = SimOnlyValueType<T>; | ||||||
|  | 
 | ||||||
|  |     fn to_sim_value(&self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(Default::default(), self.clone()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn into_sim_value(self) -> SimValue<Self::Type> { | ||||||
|  |         SimValue::from_value(Default::default(), self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										357
									
								
								crates/fayalite/src/sim/value/sim_only_value_unsafe.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								crates/fayalite/src/sim/value/sim_only_value_unsafe.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,357 @@ | ||||||
|  | // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||||
|  | // See Notices.txt for copyright information
 | ||||||
|  | 
 | ||||||
|  | //! `unsafe` parts of [`DynSimOnlyValue`]
 | ||||||
|  | 
 | ||||||
|  | use serde::{Serialize, de::DeserializeOwned}; | ||||||
|  | use std::{ | ||||||
|  |     alloc::{Layout, alloc, dealloc, handle_alloc_error}, | ||||||
|  |     any::TypeId, | ||||||
|  |     fmt, | ||||||
|  |     hash::{Hash, Hasher}, | ||||||
|  |     marker::PhantomData, | ||||||
|  |     mem::ManuallyDrop, | ||||||
|  |     ptr::{self, NonNull}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SimOnlyValueVTable { | ||||||
|  |     layout: Layout, | ||||||
|  |     // TODO: replace with TypeId once TypeId::of is const-stable
 | ||||||
|  |     type_id: fn() -> TypeId, | ||||||
|  |     type_name: fn() -> &'static str, | ||||||
|  |     drop_in_place: unsafe fn(this: NonNull<()>), | ||||||
|  |     eq: unsafe fn(this: NonNull<()>, other: NonNull<()>) -> bool, | ||||||
|  |     hash: unsafe fn(this: NonNull<()>, hasher: &mut dyn Hasher), | ||||||
|  |     debug_fmt: unsafe fn(this: NonNull<()>, f: &mut fmt::Formatter<'_>) -> fmt::Result, | ||||||
|  |     serialize_to_json_string: unsafe fn(this: NonNull<()>) -> serde_json::Result<String>, | ||||||
|  |     deserialize_into_uninit_from_json_string: | ||||||
|  |         unsafe fn(this: NonNull<()>, json_str: &str) -> serde_json::Result<()>, | ||||||
|  |     clone_into_uninit: unsafe fn(target: NonNull<()>, src: NonNull<()>), | ||||||
|  |     clone_from: unsafe fn(this: NonNull<()>, src: NonNull<()>), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait SimOnlyValueTrait: | ||||||
|  |     'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone> SimOnlyValueTrait | ||||||
|  |     for T | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsafe trait GetSimOnlyValueVTable: SimOnlyValueTrait { | ||||||
|  |     const VTABLE: &'static SimOnlyValueVTable; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsafe impl<T: SimOnlyValueTrait> GetSimOnlyValueVTable for T { | ||||||
|  |     const VTABLE: &'static SimOnlyValueVTable = &SimOnlyValueVTable { | ||||||
|  |         layout: Layout::new::<T>(), | ||||||
|  |         type_id: TypeId::of::<T>, | ||||||
|  |         type_name: std::any::type_name::<T>, | ||||||
|  |         drop_in_place: |this| unsafe { | ||||||
|  |             this.cast::<T>().drop_in_place(); | ||||||
|  |         }, | ||||||
|  |         eq: |this, other| unsafe { this.cast::<T>().as_ref() == other.cast::<T>().as_ref() }, | ||||||
|  |         hash: |this, mut hasher| unsafe { this.cast::<T>().as_ref().hash(&mut hasher) }, | ||||||
|  |         debug_fmt: |this, f| unsafe { fmt::Debug::fmt(this.cast::<T>().as_ref(), f) }, | ||||||
|  |         serialize_to_json_string: |this| unsafe { | ||||||
|  |             serde_json::to_string(this.cast::<T>().as_ref()) | ||||||
|  |         }, | ||||||
|  |         deserialize_into_uninit_from_json_string: |this, json_str| unsafe { | ||||||
|  |             serde_json::from_str(json_str).map(|v| this.cast::<T>().write(v)) | ||||||
|  |         }, | ||||||
|  |         clone_into_uninit: |target, src| unsafe { | ||||||
|  |             target | ||||||
|  |                 .cast::<T>() | ||||||
|  |                 .write(Clone::clone(src.cast::<T>().as_ref())); | ||||||
|  |         }, | ||||||
|  |         clone_from: |this, src| unsafe { | ||||||
|  |             Clone::clone_from(this.cast::<T>().as_mut(), src.cast::<T>().as_ref()); | ||||||
|  |         }, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub struct DynSimOnlyValueType { | ||||||
|  |     vtable: &'static SimOnlyValueVTable, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct DynSimOnlyValueUninit { | ||||||
|  |     ty: DynSimOnlyValueType, | ||||||
|  |     value: NonNull<()>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValueUninit { | ||||||
|  |     fn new(ty: DynSimOnlyValueType) -> Self { | ||||||
|  |         let layout = ty.vtable.layout; | ||||||
|  |         let value = if layout.size() == 0 { | ||||||
|  |             ptr::without_provenance_mut(layout.align()) | ||||||
|  |         } else { | ||||||
|  |             unsafe { alloc(layout).cast() } | ||||||
|  |         }; | ||||||
|  |         let Some(value) = NonNull::new(value) else { | ||||||
|  |             handle_alloc_error(layout) | ||||||
|  |         }; | ||||||
|  |         Self { ty, value } | ||||||
|  |     } | ||||||
|  |     unsafe fn assume_init(self) -> DynSimOnlyValue { | ||||||
|  |         let this = ManuallyDrop::new(self); | ||||||
|  |         DynSimOnlyValue { | ||||||
|  |             ty: this.ty, | ||||||
|  |             value: this.value, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Drop for DynSimOnlyValueUninit { | ||||||
|  |     fn drop(&mut self) { | ||||||
|  |         let layout = self.ty.vtable.layout; | ||||||
|  |         if layout.size() != 0 { | ||||||
|  |             unsafe { | ||||||
|  |                 dealloc(self.value.as_ptr().cast(), layout); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValueType { | ||||||
|  |     pub const fn of<T: SimOnlyValueTrait>() -> Self { | ||||||
|  |         Self { | ||||||
|  |             vtable: <T as GetSimOnlyValueVTable>::VTABLE, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn type_id(self) -> TypeId { | ||||||
|  |         (self.vtable.type_id)() | ||||||
|  |     } | ||||||
|  |     pub fn type_name(self) -> &'static str { | ||||||
|  |         (self.vtable.type_name)() | ||||||
|  |     } | ||||||
|  |     pub fn is<T: SimOnlyValueTrait>(self) -> bool { | ||||||
|  |         self.type_id() == TypeId::of::<T>() | ||||||
|  |     } | ||||||
|  |     pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnlyValueType<T>> { | ||||||
|  |         self.is::<T>().then_some(SimOnlyValueType::default()) | ||||||
|  |     } | ||||||
|  |     pub fn deserialize_from_json_string( | ||||||
|  |         self, | ||||||
|  |         json_str: &str, | ||||||
|  |     ) -> serde_json::Result<DynSimOnlyValue> { | ||||||
|  |         let retval = DynSimOnlyValueUninit::new(self); | ||||||
|  |         unsafe { | ||||||
|  |             (self.vtable.deserialize_into_uninit_from_json_string)(retval.value, json_str)?; | ||||||
|  |             Ok(retval.assume_init()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl PartialEq for DynSimOnlyValueType { | ||||||
|  |     fn eq(&self, other: &Self) -> bool { | ||||||
|  |         if ptr::eq(self.vtable, other.vtable) { | ||||||
|  |             true | ||||||
|  |         } else if self.vtable.layout != other.vtable.layout { | ||||||
|  |             false | ||||||
|  |         } else { | ||||||
|  |             (self.vtable.type_id)() == (other.vtable.type_id)() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Eq for DynSimOnlyValueType {} | ||||||
|  | 
 | ||||||
|  | impl Hash for DynSimOnlyValueType { | ||||||
|  |     fn hash<H: Hasher>(&self, state: &mut H) { | ||||||
|  |         (self.vtable.type_id)().hash(state); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl fmt::Debug for DynSimOnlyValueType { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         write!(f, "SimOnlyValueType<{}>", (self.vtable.type_name)()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> From<SimOnlyValueType<T>> for DynSimOnlyValueType { | ||||||
|  |     fn from(value: SimOnlyValueType<T>) -> Self { | ||||||
|  |         let SimOnlyValueType(PhantomData) = value; | ||||||
|  |         Self { | ||||||
|  |             vtable: <T as GetSimOnlyValueVTable>::VTABLE, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Eq, PartialEq, Hash, Debug)] | ||||||
|  | pub struct SimOnlyValueType<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>); | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> SimOnlyValueType<T> { | ||||||
|  |     pub const fn new() -> Self { | ||||||
|  |         Self(PhantomData) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> Copy for SimOnlyValueType<T> {} | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> Default for SimOnlyValueType<T> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self::new() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)] | ||||||
|  | pub struct SimOnlyValue<T: SimOnlyValueTrait>(Box<T>); | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> SimOnlyValue<T> { | ||||||
|  |     pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R { | ||||||
|  |         let dyn_ref = ManuallyDrop::new(DynSimOnlyValue { | ||||||
|  |             ty: SimOnlyValueType::<T>::default().into(), | ||||||
|  |             value: NonNull::<T>::from_ref(&self.0).cast(), | ||||||
|  |         }); | ||||||
|  |         f(&dyn_ref) | ||||||
|  |     } | ||||||
|  |     pub fn from_box(v: Box<T>) -> Self { | ||||||
|  |         Self(v) | ||||||
|  |     } | ||||||
|  |     pub fn new(v: T) -> Self { | ||||||
|  |         Self(Box::new(v)) | ||||||
|  |     } | ||||||
|  |     pub fn into_inner(this: Self) -> T { | ||||||
|  |         *this.0 | ||||||
|  |     } | ||||||
|  |     pub fn into_inner_box(this: Self) -> Box<T> { | ||||||
|  |         this.0 | ||||||
|  |     } | ||||||
|  |     pub fn into_dyn(this: Self) -> DynSimOnlyValue { | ||||||
|  |         DynSimOnlyValue::from(this) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> std::ops::Deref for SimOnlyValue<T> { | ||||||
|  |     type Target = T; | ||||||
|  |     fn deref(&self) -> &Self::Target { | ||||||
|  |         &self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> std::ops::DerefMut for SimOnlyValue<T> { | ||||||
|  |     fn deref_mut(&mut self) -> &mut Self::Target { | ||||||
|  |         &mut self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct DynSimOnlyValue { | ||||||
|  |     ty: DynSimOnlyValueType, | ||||||
|  |     value: NonNull<()>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct DebugDynSimOnlyValueInner<'a>(&'a DynSimOnlyValue); | ||||||
|  | 
 | ||||||
|  | impl<'a> fmt::Debug for DebugDynSimOnlyValueInner<'a> { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         unsafe { (self.0.ty.vtable.debug_fmt)(self.0.value, f) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl fmt::Debug for DynSimOnlyValue { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         write!(f, "SimOnlyValue<{}>", self.ty.type_name())?; | ||||||
|  |         f.debug_tuple("") | ||||||
|  |             .field(&DebugDynSimOnlyValueInner(self)) | ||||||
|  |             .finish() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl PartialEq for DynSimOnlyValue { | ||||||
|  |     fn eq(&self, other: &Self) -> bool { | ||||||
|  |         self.ty == other.ty && unsafe { (self.ty.vtable.eq)(self.value, other.value) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Eq for DynSimOnlyValue {} | ||||||
|  | 
 | ||||||
|  | impl Hash for DynSimOnlyValue { | ||||||
|  |     fn hash<H: Hasher>(&self, state: &mut H) { | ||||||
|  |         self.ty.hash(state); | ||||||
|  |         unsafe { (self.ty.vtable.hash)(self.value, state) }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Clone for DynSimOnlyValue { | ||||||
|  |     fn clone(&self) -> Self { | ||||||
|  |         let retval = DynSimOnlyValueUninit::new(self.ty); | ||||||
|  |         unsafe { | ||||||
|  |             (self.ty.vtable.clone_into_uninit)(retval.value, self.value); | ||||||
|  |             retval.assume_init() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn clone_from(&mut self, source: &Self) { | ||||||
|  |         if self.ty == source.ty { | ||||||
|  |             unsafe { (self.ty.vtable.clone_from)(self.value, source.value) }; | ||||||
|  |         } else { | ||||||
|  |             *self = source.clone(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Drop for DynSimOnlyValue { | ||||||
|  |     fn drop(&mut self) { | ||||||
|  |         unsafe { | ||||||
|  |             ptr::read(self).drop_in_place_and_keep_alloc(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue { | ||||||
|  |     fn from(value: SimOnlyValue<T>) -> Self { | ||||||
|  |         unsafe { | ||||||
|  |             Self { | ||||||
|  |                 ty: SimOnlyValueType::<T>::default().into(), | ||||||
|  |                 value: NonNull::new_unchecked(Box::into_raw(value.0)).cast::<()>(), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DynSimOnlyValue { | ||||||
|  |     pub fn ty(&self) -> DynSimOnlyValueType { | ||||||
|  |         self.ty | ||||||
|  |     } | ||||||
|  |     pub fn type_id(&self) -> TypeId { | ||||||
|  |         self.ty.type_id() | ||||||
|  |     } | ||||||
|  |     pub fn is<T: SimOnlyValueTrait>(&self) -> bool { | ||||||
|  |         self.ty.is::<T>() | ||||||
|  |     } | ||||||
|  |     pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> { | ||||||
|  |         let Some(_) = self.ty.downcast::<T>() else { | ||||||
|  |             return Err(self); | ||||||
|  |         }; | ||||||
|  |         Ok(SimOnlyValue(unsafe { | ||||||
|  |             Box::from_raw(ManuallyDrop::new(self).value.as_ptr().cast::<T>()) | ||||||
|  |         })) | ||||||
|  |     } | ||||||
|  |     pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> { | ||||||
|  |         self.ty | ||||||
|  |             .downcast::<T>() | ||||||
|  |             .map(|_| unsafe { &*self.value.as_ptr().cast::<T>() }) | ||||||
|  |     } | ||||||
|  |     pub fn downcast_mut<T: SimOnlyValueTrait>(&mut self) -> Option<&mut T> { | ||||||
|  |         self.ty | ||||||
|  |             .downcast::<T>() | ||||||
|  |             .map(|_| unsafe { &mut *self.value.as_ptr().cast::<T>() }) | ||||||
|  |     } | ||||||
|  |     pub fn serialize_to_json_string(&self) -> serde_json::Result<String> { | ||||||
|  |         unsafe { (self.ty.vtable.serialize_to_json_string)(self.value) } | ||||||
|  |     } | ||||||
|  |     fn forget_and_keep_alloc(self) -> DynSimOnlyValueUninit { | ||||||
|  |         let this = ManuallyDrop::new(self); | ||||||
|  |         DynSimOnlyValueUninit { | ||||||
|  |             ty: this.ty, | ||||||
|  |             value: this.value, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn drop_in_place_and_keep_alloc(self) -> DynSimOnlyValueUninit { | ||||||
|  |         let retval = self.forget_and_keep_alloc(); | ||||||
|  |         unsafe { (retval.ty.vtable.drop_in_place)(retval.value) }; | ||||||
|  |         retval | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -13,6 +13,7 @@ use crate::{ | ||||||
|         TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset, |         TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset, | ||||||
|         TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, |         TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, | ||||||
|         time::{SimDuration, SimInstant}, |         time::{SimDuration, SimInstant}, | ||||||
|  |         value::DynSimOnlyValue, | ||||||
|     }, |     }, | ||||||
|     util::HashMap, |     util::HashMap, | ||||||
| }; | }; | ||||||
|  | @ -1061,6 +1062,14 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> { | ||||||
|     ) -> Result<(), Self::Error> { |     ) -> Result<(), Self::Error> { | ||||||
|         write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize()) |         write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize()) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fn set_signal_sim_only_value( | ||||||
|  |         &mut self, | ||||||
|  |         id: TraceScalarId, | ||||||
|  |         value: &DynSimOnlyValue, | ||||||
|  |     ) -> Result<(), Self::Error> { | ||||||
|  |         write_string_value_change(&mut self.writer, format_args!("{value:?}"), id) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<W: io::Write> fmt::Debug for VcdWriter<W> { | impl<W: io::Write> fmt::Debug for VcdWriter<W> { | ||||||
|  |  | ||||||
|  | @ -11,13 +11,21 @@ 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}, |     sim::value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     util::ConstUsize, |     util::{ConstUsize, slice_range, try_slice_range}, | ||||||
| }; | }; | ||||||
| use bitvec::slice::BitSlice; | use bitvec::{slice::BitSlice, vec::BitVec}; | ||||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; | use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; | ||||||
| use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index, sync::Arc}; | use std::{ | ||||||
|  |     fmt, | ||||||
|  |     hash::Hash, | ||||||
|  |     iter::{FusedIterator, Sum}, | ||||||
|  |     marker::PhantomData, | ||||||
|  |     mem, | ||||||
|  |     ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign}, | ||||||
|  |     sync::Arc, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| pub(crate) mod serde_impls; | pub(crate) mod serde_impls; | ||||||
| 
 | 
 | ||||||
|  | @ -28,6 +36,23 @@ pub struct TypeProperties { | ||||||
|     pub is_storable: bool, |     pub is_storable: bool, | ||||||
|     pub is_castable_from_bits: bool, |     pub is_castable_from_bits: bool, | ||||||
|     pub bit_width: usize, |     pub bit_width: usize, | ||||||
|  |     pub sim_only_values_len: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl TypeProperties { | ||||||
|  |     pub const fn size(self) -> OpaqueSimValueSize { | ||||||
|  |         let Self { | ||||||
|  |             is_passive: _, | ||||||
|  |             is_storable: _, | ||||||
|  |             is_castable_from_bits: _, | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } = self; | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Copy, Clone, Hash, PartialEq, Eq)] | #[derive(Copy, Clone, Hash, PartialEq, Eq)] | ||||||
|  | @ -43,6 +68,7 @@ pub enum CanonicalType { | ||||||
|     Reset(Reset), |     Reset(Reset), | ||||||
|     Clock(Clock), |     Clock(Clock), | ||||||
|     PhantomConst(PhantomConst), |     PhantomConst(PhantomConst), | ||||||
|  |     DynSimOnlyValueType(DynSimOnlyValueType), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl fmt::Debug for CanonicalType { | impl fmt::Debug for CanonicalType { | ||||||
|  | @ -59,6 +85,7 @@ impl fmt::Debug for CanonicalType { | ||||||
|             Self::Reset(v) => v.fmt(f), |             Self::Reset(v) => v.fmt(f), | ||||||
|             Self::Clock(v) => v.fmt(f), |             Self::Clock(v) => v.fmt(f), | ||||||
|             Self::PhantomConst(v) => v.fmt(f), |             Self::PhantomConst(v) => v.fmt(f), | ||||||
|  |             Self::DynSimOnlyValueType(v) => v.fmt(f), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -95,6 +122,7 @@ impl CanonicalType { | ||||||
|             CanonicalType::Reset(v) => v.type_properties(), |             CanonicalType::Reset(v) => v.type_properties(), | ||||||
|             CanonicalType::Clock(v) => v.type_properties(), |             CanonicalType::Clock(v) => v.type_properties(), | ||||||
|             CanonicalType::PhantomConst(v) => v.type_properties(), |             CanonicalType::PhantomConst(v) => v.type_properties(), | ||||||
|  |             CanonicalType::DynSimOnlyValueType(v) => v.type_properties(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     pub fn is_passive(self) -> bool { |     pub fn is_passive(self) -> bool { | ||||||
|  | @ -109,6 +137,12 @@ impl CanonicalType { | ||||||
|     pub fn bit_width(self) -> usize { |     pub fn bit_width(self) -> usize { | ||||||
|         self.type_properties().bit_width |         self.type_properties().bit_width | ||||||
|     } |     } | ||||||
|  |     pub fn sim_only_values_len(self) -> usize { | ||||||
|  |         self.type_properties().sim_only_values_len | ||||||
|  |     } | ||||||
|  |     pub fn size(self) -> OpaqueSimValueSize { | ||||||
|  |         self.type_properties().size() | ||||||
|  |     } | ||||||
|     pub fn can_connect(self, rhs: Self) -> bool { |     pub fn can_connect(self, rhs: Self) -> bool { | ||||||
|         match self { |         match self { | ||||||
|             CanonicalType::UInt(lhs) => { |             CanonicalType::UInt(lhs) => { | ||||||
|  | @ -177,6 +211,12 @@ impl CanonicalType { | ||||||
|                 }; |                 }; | ||||||
|                 lhs.can_connect(rhs) |                 lhs.can_connect(rhs) | ||||||
|             } |             } | ||||||
|  |             CanonicalType::DynSimOnlyValueType(lhs) => { | ||||||
|  |                 let CanonicalType::DynSimOnlyValueType(rhs) = rhs else { | ||||||
|  |                     return false; | ||||||
|  |                 }; | ||||||
|  |                 lhs.can_connect(rhs) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     pub(crate) fn as_serde_unexpected_str(self) -> &'static str { |     pub(crate) fn as_serde_unexpected_str(self) -> &'static str { | ||||||
|  | @ -287,6 +327,7 @@ impl_base_type!(SyncReset); | ||||||
| impl_base_type!(Reset); | impl_base_type!(Reset); | ||||||
| impl_base_type!(Clock); | impl_base_type!(Clock); | ||||||
| impl_base_type!(PhantomConst); | impl_base_type!(PhantomConst); | ||||||
|  | impl_base_type!(DynSimOnlyValueType); | ||||||
| 
 | 
 | ||||||
| impl_base_type_serde!(Bool, "a Bool"); | impl_base_type_serde!(Bool, "a Bool"); | ||||||
| impl_base_type_serde!(Enum, "an Enum"); | impl_base_type_serde!(Enum, "an Enum"); | ||||||
|  | @ -348,9 +389,17 @@ pub trait Type: | ||||||
|     fn canonical(&self) -> CanonicalType; |     fn canonical(&self) -> CanonicalType; | ||||||
|     fn from_canonical(canonical_type: CanonicalType) -> Self; |     fn from_canonical(canonical_type: CanonicalType) -> Self; | ||||||
|     fn source_location() -> SourceLocation; |     fn source_location() -> SourceLocation; | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue; |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue; | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice); |     fn sim_value_clone_from_opaque( | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice); |         &self, | ||||||
|  |         value: &mut Self::SimValue, | ||||||
|  |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ); | ||||||
|  |     fn sim_value_to_opaque<'w>( | ||||||
|  |         &self, | ||||||
|  |         value: &Self::SimValue, | ||||||
|  |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait BaseType: | pub trait BaseType: | ||||||
|  | @ -405,6 +454,7 @@ impl Type for CanonicalType { | ||||||
|             CanonicalType::Reset(v) => v.mask_type().canonical(), |             CanonicalType::Reset(v) => v.mask_type().canonical(), | ||||||
|             CanonicalType::Clock(v) => v.mask_type().canonical(), |             CanonicalType::Clock(v) => v.mask_type().canonical(), | ||||||
|             CanonicalType::PhantomConst(v) => v.mask_type().canonical(), |             CanonicalType::PhantomConst(v) => v.mask_type().canonical(), | ||||||
|  |             CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn canonical(&self) -> CanonicalType { |     fn canonical(&self) -> CanonicalType { | ||||||
|  | @ -416,28 +466,288 @@ impl Type for CanonicalType { | ||||||
|     fn source_location() -> SourceLocation { |     fn source_location() -> SourceLocation { | ||||||
|         SourceLocation::builtin() |         SourceLocation::builtin() | ||||||
|     } |     } | ||||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { |     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||||
|         assert_eq!(bits.len(), self.bit_width()); |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|         OpaqueSimValue::from_bitslice(bits) |         opaque.to_owned() | ||||||
|     } |     } | ||||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { |     fn sim_value_clone_from_opaque( | ||||||
|         assert_eq!(bits.len(), self.bit_width()); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.bit_width()); |         value: &mut Self::SimValue, | ||||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); |         opaque: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) { | ||||||
|  |         assert_eq!(self.type_properties().size(), opaque.size()); | ||||||
|  |         assert_eq!(value.size(), opaque.size()); | ||||||
|  |         value.clone_from_slice(opaque); | ||||||
|     } |     } | ||||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { |     fn sim_value_to_opaque<'w>( | ||||||
|         assert_eq!(bits.len(), self.bit_width()); |         &self, | ||||||
|         assert_eq!(value.bit_width(), self.bit_width()); |         value: &Self::SimValue, | ||||||
|         bits.copy_from_bitslice(value.bits().bits()); |         writer: OpaqueSimValueWriter<'w>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'w> { | ||||||
|  |         assert_eq!(self.type_properties().size(), writer.size()); | ||||||
|  |         assert_eq!(value.size(), writer.size()); | ||||||
|  |         writer.fill_cloned_from_slice(value.as_slice()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)] | ||||||
|  | #[non_exhaustive] | ||||||
|  | pub struct OpaqueSimValueSizeRange { | ||||||
|  |     pub bit_width: Range<usize>, | ||||||
|  |     pub sim_only_values_len: Range<usize>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OpaqueSimValueSizeRange { | ||||||
|  |     pub fn start(&self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.bit_width.start, | ||||||
|  |             sim_only_values_len: self.sim_only_values_len.start, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn end(&self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.bit_width.end, | ||||||
|  |             sim_only_values_len: self.sim_only_values_len.end, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_empty(&self) -> bool { | ||||||
|  |         let Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } = self; | ||||||
|  |         bit_width.is_empty() && sim_only_values_len.is_empty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Range<OpaqueSimValueSize>> for OpaqueSimValueSizeRange { | ||||||
|  |     fn from(value: Range<OpaqueSimValueSize>) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bit_width: value.start.bit_width..value.end.bit_width, | ||||||
|  |             sim_only_values_len: value.start.sim_only_values_len..value.end.sim_only_values_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<OpaqueSimValueSizeRange> for Range<OpaqueSimValueSize> { | ||||||
|  |     fn from(value: OpaqueSimValueSizeRange) -> Self { | ||||||
|  |         value.start()..value.end() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait OpaqueSimValueSizeRangeBounds { | ||||||
|  |     fn start_bound(&self) -> Bound<OpaqueSimValueSize>; | ||||||
|  |     fn end_bound(&self) -> Bound<OpaqueSimValueSize>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OpaqueSimValueSizeRangeBounds for OpaqueSimValueSizeRange { | ||||||
|  |     fn start_bound(&self) -> Bound<OpaqueSimValueSize> { | ||||||
|  |         Bound::Included(self.start()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn end_bound(&self) -> Bound<OpaqueSimValueSize> { | ||||||
|  |         Bound::Excluded(self.end()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized + std::ops::RangeBounds<OpaqueSimValueSize>> OpaqueSimValueSizeRangeBounds for T { | ||||||
|  |     fn start_bound(&self) -> Bound<OpaqueSimValueSize> { | ||||||
|  |         std::ops::RangeBounds::start_bound(self).cloned() | ||||||
|  |     } | ||||||
|  |     fn end_bound(&self) -> Bound<OpaqueSimValueSize> { | ||||||
|  |         std::ops::RangeBounds::end_bound(self).cloned() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)] | ||||||
|  | #[non_exhaustive] | ||||||
|  | pub struct OpaqueSimValueSize { | ||||||
|  |     pub bit_width: usize, | ||||||
|  |     pub sim_only_values_len: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OpaqueSimValueSize { | ||||||
|  |     pub const fn from_bit_width(bit_width: usize) -> Self { | ||||||
|  |         Self::from_bit_width_and_sim_only_values_len(bit_width, 0) | ||||||
|  |     } | ||||||
|  |     pub const fn from_bit_width_and_sim_only_values_len( | ||||||
|  |         bit_width: usize, | ||||||
|  |         sim_only_values_len: usize, | ||||||
|  |     ) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub const fn empty() -> Self { | ||||||
|  |         Self { | ||||||
|  |             bit_width: 0, | ||||||
|  |             sim_only_values_len: 0, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub const fn is_empty(self) -> bool { | ||||||
|  |         let Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } = self; | ||||||
|  |         bit_width == 0 && sim_only_values_len == 0 | ||||||
|  |     } | ||||||
|  |     pub const fn checked_mul(self, factor: usize) -> Option<Self> { | ||||||
|  |         let Some(bit_width) = self.bit_width.checked_mul(factor) else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         let Some(sim_only_values_len) = self.sim_only_values_len.checked_mul(factor) else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         Some(Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |     pub const fn checked_add(self, rhs: Self) -> Option<Self> { | ||||||
|  |         let Some(bit_width) = self.bit_width.checked_add(rhs.bit_width) else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         let Some(sim_only_values_len) = self | ||||||
|  |             .sim_only_values_len | ||||||
|  |             .checked_add(rhs.sim_only_values_len) | ||||||
|  |         else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         Some(Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |     pub const fn checked_sub(self, rhs: Self) -> Option<Self> { | ||||||
|  |         let Some(bit_width) = self.bit_width.checked_sub(rhs.bit_width) else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         let Some(sim_only_values_len) = self | ||||||
|  |             .sim_only_values_len | ||||||
|  |             .checked_sub(rhs.sim_only_values_len) | ||||||
|  |         else { | ||||||
|  |             return None; | ||||||
|  |         }; | ||||||
|  |         Some(Self { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |     pub fn try_slice_range<R: OpaqueSimValueSizeRangeBounds>( | ||||||
|  |         self, | ||||||
|  |         range: R, | ||||||
|  |     ) -> Option<OpaqueSimValueSizeRange> { | ||||||
|  |         let start = range.start_bound(); | ||||||
|  |         let end = range.end_bound(); | ||||||
|  |         let bit_width = try_slice_range( | ||||||
|  |             (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), | ||||||
|  |             self.bit_width, | ||||||
|  |         )?; | ||||||
|  |         let sim_only_values_len = try_slice_range( | ||||||
|  |             ( | ||||||
|  |                 start.map(|v| v.sim_only_values_len), | ||||||
|  |                 end.map(|v| v.sim_only_values_len), | ||||||
|  |             ), | ||||||
|  |             self.sim_only_values_len, | ||||||
|  |         )?; | ||||||
|  |         Some(OpaqueSimValueSizeRange { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |     pub fn slice_range<R: OpaqueSimValueSizeRangeBounds>( | ||||||
|  |         self, | ||||||
|  |         range: R, | ||||||
|  |     ) -> OpaqueSimValueSizeRange { | ||||||
|  |         self.try_slice_range(range).expect("range out of bounds") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Mul<usize> for OpaqueSimValueSize { | ||||||
|  |     type Output = OpaqueSimValueSize; | ||||||
|  | 
 | ||||||
|  |     fn mul(self, rhs: usize) -> Self::Output { | ||||||
|  |         self.checked_mul(rhs).expect("multiplication overflowed") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Mul<OpaqueSimValueSize> for usize { | ||||||
|  |     type Output = OpaqueSimValueSize; | ||||||
|  | 
 | ||||||
|  |     fn mul(self, rhs: OpaqueSimValueSize) -> Self::Output { | ||||||
|  |         rhs.checked_mul(self).expect("multiplication overflowed") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Add for OpaqueSimValueSize { | ||||||
|  |     type Output = OpaqueSimValueSize; | ||||||
|  | 
 | ||||||
|  |     fn add(self, rhs: OpaqueSimValueSize) -> Self::Output { | ||||||
|  |         rhs.checked_add(self).expect("addition overflowed") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Sub for OpaqueSimValueSize { | ||||||
|  |     type Output = OpaqueSimValueSize; | ||||||
|  | 
 | ||||||
|  |     fn sub(self, rhs: OpaqueSimValueSize) -> Self::Output { | ||||||
|  |         rhs.checked_sub(self).expect("subtraction underflowed") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl MulAssign<usize> for OpaqueSimValueSize { | ||||||
|  |     fn mul_assign(&mut self, rhs: usize) { | ||||||
|  |         *self = *self * rhs; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl AddAssign for OpaqueSimValueSize { | ||||||
|  |     fn add_assign(&mut self, rhs: OpaqueSimValueSize) { | ||||||
|  |         *self = *self + rhs; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SubAssign for OpaqueSimValueSize { | ||||||
|  |     fn sub_assign(&mut self, rhs: OpaqueSimValueSize) { | ||||||
|  |         *self = *self - rhs; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Sum for OpaqueSimValueSize { | ||||||
|  |     fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { | ||||||
|  |         iter.fold(OpaqueSimValueSize::empty(), Add::add) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] | #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] | ||||||
| pub struct OpaqueSimValue { | pub struct OpaqueSimValue { | ||||||
|     bits: UIntValue, |     bits: UIntValue, | ||||||
|  |     #[serde(skip_serializing_if = "Vec::is_empty", default)] | ||||||
|  |     sim_only_values: Vec<DynSimOnlyValue>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl OpaqueSimValue { | impl OpaqueSimValue { | ||||||
|  |     pub fn empty() -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits: UIntValue::new(Default::default()), | ||||||
|  |             sim_only_values: Vec::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn with_capacity(capacity: OpaqueSimValueSize) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits: UIntValue::new(Arc::new(BitVec::with_capacity(capacity.bit_width))), | ||||||
|  |             sim_only_values: Vec::with_capacity(capacity.sim_only_values_len), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn size(&self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.bits.width(), | ||||||
|  |             sim_only_values_len: self.sim_only_values.len(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_empty(&self) -> bool { | ||||||
|  |         self.size().is_empty() | ||||||
|  |     } | ||||||
|     pub fn bit_width(&self) -> usize { |     pub fn bit_width(&self) -> usize { | ||||||
|         self.bits.width() |         self.bits.width() | ||||||
|     } |     } | ||||||
|  | @ -451,11 +761,109 @@ impl OpaqueSimValue { | ||||||
|         self.bits |         self.bits | ||||||
|     } |     } | ||||||
|     pub fn from_bits(bits: UIntValue) -> Self { |     pub fn from_bits(bits: UIntValue) -> Self { | ||||||
|         Self { bits } |         Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values: Vec::new(), | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     pub fn from_bitslice(v: &BitSlice) -> Self { |     pub fn from_bitslice(v: &BitSlice) -> Self { | ||||||
|  |         Self::from_bitslice_and_sim_only_values(v, Vec::new()) | ||||||
|  |     } | ||||||
|  |     pub fn from_bitslice_and_sim_only_values( | ||||||
|  |         bits: &BitSlice, | ||||||
|  |         sim_only_values: Vec<DynSimOnlyValue>, | ||||||
|  |     ) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             bits: UIntValue::new(Arc::new(v.to_bitvec())), |             bits: UIntValue::new(Arc::new(bits.to_bitvec())), | ||||||
|  |             sim_only_values, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn from_bits_and_sim_only_values( | ||||||
|  |         bits: UIntValue, | ||||||
|  |         sim_only_values: Vec<DynSimOnlyValue>, | ||||||
|  |     ) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn into_parts(self) -> (UIntValue, Vec<DynSimOnlyValue>) { | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = self; | ||||||
|  |         (bits, sim_only_values) | ||||||
|  |     } | ||||||
|  |     pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec<DynSimOnlyValue>) { | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = self; | ||||||
|  |         (bits, sim_only_values) | ||||||
|  |     } | ||||||
|  |     pub fn sim_only_values(&self) -> &[DynSimOnlyValue] { | ||||||
|  |         &self.sim_only_values | ||||||
|  |     } | ||||||
|  |     pub fn sim_only_values_mut(&mut self) -> &mut Vec<DynSimOnlyValue> { | ||||||
|  |         &mut self.sim_only_values | ||||||
|  |     } | ||||||
|  |     pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> { | ||||||
|  |         OpaqueSimValueSlice { | ||||||
|  |             bits: self.bits.bits(), | ||||||
|  |             sim_only_values: &self.sim_only_values, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn slice<R: OpaqueSimValueSizeRangeBounds>(&self, range: R) -> OpaqueSimValueSlice<'_> { | ||||||
|  |         self.as_slice().slice(range) | ||||||
|  |     } | ||||||
|  |     pub fn rewrite_with<F>(&mut self, target_size: OpaqueSimValueSize, f: F) | ||||||
|  |     where | ||||||
|  |         F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
 | ||||||
|  |     { | ||||||
|  |         OpaqueSimValueWriter::rewrite_with(target_size, self, f); | ||||||
|  |     } | ||||||
|  |     pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) { | ||||||
|  |         let OpaqueSimValueSlice { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = slice; | ||||||
|  |         self.bits.bits_mut().copy_from_bitslice(bits); | ||||||
|  |         self.sim_only_values.clone_from_slice(sim_only_values); | ||||||
|  |     } | ||||||
|  |     pub fn extend_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) { | ||||||
|  |         let OpaqueSimValueSlice { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = slice; | ||||||
|  |         self.bits.bitvec_mut().extend_from_bitslice(bits); | ||||||
|  |         self.sim_only_values.extend_from_slice(sim_only_values); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> Extend<OpaqueSimValueSlice<'a>> for OpaqueSimValue { | ||||||
|  |     fn extend<T: IntoIterator<Item = OpaqueSimValueSlice<'a>>>(&mut self, iter: T) { | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = self; | ||||||
|  |         let bits = bits.bitvec_mut(); | ||||||
|  |         for slice in iter { | ||||||
|  |             bits.extend_from_bitslice(slice.bits); | ||||||
|  |             sim_only_values.extend_from_slice(slice.sim_only_values); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Extend<OpaqueSimValue> for OpaqueSimValue { | ||||||
|  |     fn extend<T: IntoIterator<Item = OpaqueSimValue>>(&mut self, iter: T) { | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } = self; | ||||||
|  |         let bits = bits.bitvec_mut(); | ||||||
|  |         for value in iter { | ||||||
|  |             bits.extend_from_bitslice(value.bits().bits()); | ||||||
|  |             sim_only_values.extend_from_slice(value.sim_only_values()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -469,6 +877,207 @@ impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValu | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Copy, Clone, Debug)] | ||||||
|  | pub struct OpaqueSimValueSlice<'a> { | ||||||
|  |     bits: &'a BitSlice, | ||||||
|  |     sim_only_values: &'a [DynSimOnlyValue], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> Default for OpaqueSimValueSlice<'a> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self::empty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> OpaqueSimValueSlice<'a> { | ||||||
|  |     pub fn from_parts(bits: &'a BitSlice, sim_only_values: &'a [DynSimOnlyValue]) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn from_bitslice(bits: &'a BitSlice) -> Self { | ||||||
|  |         Self::from_parts(bits, &[]) | ||||||
|  |     } | ||||||
|  |     pub fn empty() -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits: BitSlice::empty(), | ||||||
|  |             sim_only_values: &[], | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn size(self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.bit_width(), | ||||||
|  |             sim_only_values_len: self.sim_only_values_len(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_empty(self) -> bool { | ||||||
|  |         self.size().is_empty() | ||||||
|  |     } | ||||||
|  |     pub fn bit_width(self) -> usize { | ||||||
|  |         self.bits.len() | ||||||
|  |     } | ||||||
|  |     pub fn bits(self) -> &'a BitSlice { | ||||||
|  |         self.bits | ||||||
|  |     } | ||||||
|  |     pub fn sim_only_values(self) -> &'a [DynSimOnlyValue] { | ||||||
|  |         self.sim_only_values | ||||||
|  |     } | ||||||
|  |     pub fn sim_only_values_len(self) -> usize { | ||||||
|  |         self.sim_only_values.len() | ||||||
|  |     } | ||||||
|  |     pub fn to_owned(self) -> OpaqueSimValue { | ||||||
|  |         OpaqueSimValue::from_bitslice_and_sim_only_values(self.bits, self.sim_only_values.to_vec()) | ||||||
|  |     } | ||||||
|  |     pub fn slice<R: OpaqueSimValueSizeRangeBounds>(self, range: R) -> OpaqueSimValueSlice<'a> { | ||||||
|  |         let start = range.start_bound(); | ||||||
|  |         let end = range.end_bound(); | ||||||
|  |         let bits_range = slice_range( | ||||||
|  |             (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), | ||||||
|  |             self.bit_width(), | ||||||
|  |         ); | ||||||
|  |         let sim_only_values_range = slice_range( | ||||||
|  |             (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), | ||||||
|  |             self.sim_only_values_len(), | ||||||
|  |         ); | ||||||
|  |         Self { | ||||||
|  |             bits: &self.bits[bits_range], | ||||||
|  |             sim_only_values: &self.sim_only_values[sim_only_values_range], | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn split_at(self, index: OpaqueSimValueSize) -> (Self, Self) { | ||||||
|  |         let bits = self.bits.split_at(index.bit_width); | ||||||
|  |         let sim_only_values = self.sim_only_values.split_at(index.sim_only_values_len); | ||||||
|  |         ( | ||||||
|  |             Self { | ||||||
|  |                 bits: bits.0, | ||||||
|  |                 sim_only_values: sim_only_values.0, | ||||||
|  |             }, | ||||||
|  |             Self { | ||||||
|  |                 bits: bits.1, | ||||||
|  |                 sim_only_values: sim_only_values.1, | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct OpaqueSimValueWriter<'a> { | ||||||
|  |     bits: &'a mut BitSlice, | ||||||
|  |     sim_only_values: &'a mut Vec<DynSimOnlyValue>, | ||||||
|  |     sim_only_values_range: std::ops::Range<usize>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct OpaqueSimValueWritten<'a> { | ||||||
|  |     _phantom: PhantomData<&'a ()>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> OpaqueSimValueWriter<'a> { | ||||||
|  |     pub fn rewrite_with<F>(target_size: OpaqueSimValueSize, value: &mut OpaqueSimValue, f: F) | ||||||
|  |     where | ||||||
|  |         F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
 | ||||||
|  |     { | ||||||
|  |         let OpaqueSimValueWritten { | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } = f(OpaqueSimValueWriter::rewrite_helper(target_size, value)); | ||||||
|  |     } | ||||||
|  |     pub(crate) fn rewrite_helper( | ||||||
|  |         target_size: OpaqueSimValueSize, | ||||||
|  |         value: &'a mut OpaqueSimValue, | ||||||
|  |     ) -> Self { | ||||||
|  |         let (bits, sim_only_values) = value.parts_mut(); | ||||||
|  |         let OpaqueSimValueSize { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } = target_size; | ||||||
|  |         let bits = bits.bitvec_mut(); | ||||||
|  |         bits.resize(bit_width, false); | ||||||
|  |         sim_only_values.truncate(sim_only_values_len); | ||||||
|  |         sim_only_values.reserve_exact(sim_only_values_len - sim_only_values.len()); | ||||||
|  |         Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |             sim_only_values_range: 0..sim_only_values_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn size(&self) -> OpaqueSimValueSize { | ||||||
|  |         OpaqueSimValueSize { | ||||||
|  |             bit_width: self.bit_width(), | ||||||
|  |             sim_only_values_len: self.sim_only_values_len(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn bit_width(&self) -> usize { | ||||||
|  |         self.bits.len() | ||||||
|  |     } | ||||||
|  |     pub fn sim_only_values_len(&self) -> usize { | ||||||
|  |         self.sim_only_values_range.len() | ||||||
|  |     } | ||||||
|  |     pub fn is_empty(&self) -> bool { | ||||||
|  |         self.size().is_empty() | ||||||
|  |     } | ||||||
|  |     pub fn fill_cloned_from_slice( | ||||||
|  |         self, | ||||||
|  |         slice: OpaqueSimValueSlice<'_>, | ||||||
|  |     ) -> OpaqueSimValueWritten<'a> { | ||||||
|  |         assert_eq!(self.size(), slice.size()); | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |             sim_only_values_range, | ||||||
|  |         } = self; | ||||||
|  |         bits.copy_from_bitslice(slice.bits); | ||||||
|  |         let (clone_from_src, clone_src) = slice.sim_only_values.split_at( | ||||||
|  |             (sim_only_values.len() - sim_only_values_range.start).min(slice.sim_only_values.len()), | ||||||
|  |         ); | ||||||
|  |         sim_only_values[sim_only_values_range][..clone_from_src.len()] | ||||||
|  |             .clone_from_slice(clone_from_src); | ||||||
|  |         sim_only_values.extend_from_slice(clone_src); | ||||||
|  |         OpaqueSimValueWritten { | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn fill_with_zeros(self) -> OpaqueSimValueWritten<'a> { | ||||||
|  |         assert_eq!( | ||||||
|  |             self.size(), | ||||||
|  |             OpaqueSimValueSize::from_bit_width(self.bit_width()), | ||||||
|  |             "can't fill things other than bits with zeros", | ||||||
|  |         ); | ||||||
|  |         let Self { | ||||||
|  |             bits, | ||||||
|  |             sim_only_values, | ||||||
|  |             sim_only_values_range, | ||||||
|  |         } = self; | ||||||
|  |         bits.fill(false); | ||||||
|  |         assert_eq!(sim_only_values.len(), sim_only_values_range.end); | ||||||
|  |         OpaqueSimValueWritten { | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn fill_prefix_with<F>(&mut self, prefix_size: OpaqueSimValueSize, f: F) | ||||||
|  |     where | ||||||
|  |         F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
 | ||||||
|  |     { | ||||||
|  |         let OpaqueSimValueSize { | ||||||
|  |             bit_width, | ||||||
|  |             sim_only_values_len, | ||||||
|  |         } = prefix_size; | ||||||
|  |         assert!(bit_width <= self.bit_width()); | ||||||
|  |         assert!(sim_only_values_len <= self.sim_only_values_len()); | ||||||
|  |         let next_start = self.sim_only_values_range.start + sim_only_values_len; | ||||||
|  |         let OpaqueSimValueWritten { | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } = f(OpaqueSimValueWriter { | ||||||
|  |             bits: &mut self.bits[..bit_width], | ||||||
|  |             sim_only_values: self.sim_only_values, | ||||||
|  |             sim_only_values_range: self.sim_only_values_range.start..next_start, | ||||||
|  |         }); | ||||||
|  |         assert!(self.sim_only_values.len() >= next_start); | ||||||
|  |         self.bits = &mut mem::take(&mut self.bits)[bit_width..]; | ||||||
|  |         self.sim_only_values_range.start = next_start; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub trait StaticType: Type + Default { | pub trait StaticType: Type + Default { | ||||||
|     const TYPE: Self; |     const TYPE: Self; | ||||||
|     const MASK_TYPE: Self::MaskType; |     const MASK_TYPE: Self::MaskType; | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ use crate::{ | ||||||
|     phantom_const::{PhantomConstCanonicalValue, PhantomConstValue}, |     phantom_const::{PhantomConstCanonicalValue, PhantomConstValue}, | ||||||
|     prelude::PhantomConst, |     prelude::PhantomConst, | ||||||
|     reset::{AsyncReset, Reset, SyncReset}, |     reset::{AsyncReset, Reset, SyncReset}, | ||||||
|  |     sim::value::DynSimOnlyValueType, | ||||||
|     ty::{BaseType, CanonicalType}, |     ty::{BaseType, CanonicalType}, | ||||||
| }; | }; | ||||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||||
|  | @ -63,6 +64,7 @@ pub(crate) enum SerdeCanonicalType< | ||||||
|     Reset, |     Reset, | ||||||
|     Clock, |     Clock, | ||||||
|     PhantomConst(ThePhantomConst), |     PhantomConst(ThePhantomConst), | ||||||
|  |     DynSimOnlyValueType(DynSimOnlyValueType), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> { | impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> { | ||||||
|  | @ -79,6 +81,7 @@ impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomCo | ||||||
|             Self::Reset => "a Reset", |             Self::Reset => "a Reset", | ||||||
|             Self::Clock => "a Clock", |             Self::Clock => "a Clock", | ||||||
|             Self::PhantomConst(_) => "a PhantomConst", |             Self::PhantomConst(_) => "a PhantomConst", | ||||||
|  |             Self::DynSimOnlyValueType(_) => "a SimOnlyValue", | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -105,6 +108,7 @@ impl<T: BaseType> From<T> for SerdeCanonicalType { | ||||||
|             CanonicalType::Reset(Reset {}) => Self::Reset, |             CanonicalType::Reset(Reset {}) => Self::Reset, | ||||||
|             CanonicalType::Clock(Clock {}) => Self::Clock, |             CanonicalType::Clock(Clock {}) => Self::Clock, | ||||||
|             CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())), |             CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())), | ||||||
|  |             CanonicalType::DynSimOnlyValueType(ty) => Self::DynSimOnlyValueType(ty), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -125,6 +129,7 @@ impl From<SerdeCanonicalType> for CanonicalType { | ||||||
|             SerdeCanonicalType::PhantomConst(value) => { |             SerdeCanonicalType::PhantomConst(value) => { | ||||||
|                 Self::PhantomConst(PhantomConst::new(value.0)) |                 Self::PhantomConst(PhantomConst::new(value.0)) | ||||||
|             } |             } | ||||||
|  |             SerdeCanonicalType::DynSimOnlyValueType(value) => Self::DynSimOnlyValueType(value), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ pub use scoped_ref::ScopedRef; | ||||||
| #[doc(inline)] | #[doc(inline)] | ||||||
| pub use misc::{ | pub use misc::{ | ||||||
|     BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, |     BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, | ||||||
|     iter_eq_by, |     iter_eq_by, slice_range, try_slice_range, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub mod job_server; | pub mod job_server; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView}; | ||||||
| use std::{ | use std::{ | ||||||
|     cell::Cell, |     cell::Cell, | ||||||
|     fmt::{self, Debug, Write}, |     fmt::{self, Debug, Write}, | ||||||
|  |     ops::{Bound, Range, RangeBounds}, | ||||||
|     rc::Rc, |     rc::Rc, | ||||||
|     sync::{Arc, OnceLock}, |     sync::{Arc, OnceLock}, | ||||||
| }; | }; | ||||||
|  | @ -209,3 +210,21 @@ impl std::io::Write for RcWriter { | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub fn try_slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Option<Range<usize>> { | ||||||
|  |     let start = match range.start_bound() { | ||||||
|  |         Bound::Included(start) => *start, | ||||||
|  |         Bound::Excluded(start) => start.checked_add(1)?, | ||||||
|  |         Bound::Unbounded => 0, | ||||||
|  |     }; | ||||||
|  |     let end = match range.end_bound() { | ||||||
|  |         Bound::Included(end) => end.checked_add(1)?, | ||||||
|  |         Bound::Excluded(end) => *end, | ||||||
|  |         Bound::Unbounded => size, | ||||||
|  |     }; | ||||||
|  |     (start <= end && end <= size).then_some(start..end) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Range<usize> { | ||||||
|  |     try_slice_range(range, size).expect("range out of bounds") | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue