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 ident: &Ident = field.ident().as_ref().unwrap(); | ||||
|             quote_spanned! {span=> | ||||
|                 #ident: v.field_from_bits(), | ||||
|             } | ||||
|         })); | ||||
|         let sim_value_clone_from_bits_fields = | ||||
|         let sim_value_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_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_to_bits(&value.#ident); | ||||
|                     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(); | ||||
|             quote_spanned! {span=> | ||||
|                 v.field(&value.#ident); | ||||
|             } | ||||
|         })); | ||||
|         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 { | ||||
|                     ::fayalite::source_location::SourceLocation::caller() | ||||
|                 } | ||||
|                 fn sim_value_from_bits( | ||||
|                 fn sim_value_from_opaque( | ||||
|                     &self, | ||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, | ||||
|                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||
|                 ) -> <Self as ::fayalite::ty::Type>::SimValue { | ||||
|                     #![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 { | ||||
|                         #(#sim_value_from_bits_fields)* | ||||
|                         #(#sim_value_from_opaque_fields)* | ||||
|                     } | ||||
|                 } | ||||
|                 fn sim_value_clone_from_bits( | ||||
|                 fn sim_value_clone_from_opaque( | ||||
|                     &self, | ||||
|                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, | ||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, | ||||
|                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||
|                 ) { | ||||
|                     #![allow(unused_mut, unused_variables)] | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); | ||||
|                     #(#sim_value_clone_from_bits_fields)* | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||
|                     #(#sim_value_clone_from_opaque_fields)* | ||||
|                 } | ||||
|                 fn sim_value_to_bits( | ||||
|                 fn sim_value_to_opaque<'__w>( | ||||
|                     &self, | ||||
|                     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)] | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); | ||||
|                     #(#sim_value_to_bits_fields)* | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); | ||||
|                     #(#sim_value_to_opaque_fields)* | ||||
|                     v.finish() | ||||
|                 } | ||||
|             } | ||||
|             #[automatically_derived] | ||||
|  | @ -894,33 +896,34 @@ impl ToTokens for ParsedBundle { | |||
|                 fn source_location() -> ::fayalite::source_location::SourceLocation { | ||||
|                     ::fayalite::source_location::SourceLocation::caller() | ||||
|                 } | ||||
|                 fn sim_value_from_bits( | ||||
|                 fn sim_value_from_opaque( | ||||
|                     &self, | ||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, | ||||
|                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||
|                 ) -> <Self as ::fayalite::ty::Type>::SimValue { | ||||
|                     #![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_from_bits_fields)* | ||||
|                         #(#sim_value_from_opaque_fields)* | ||||
|                     } | ||||
|                 } | ||||
|                 fn sim_value_clone_from_bits( | ||||
|                 fn sim_value_clone_from_opaque( | ||||
|                     &self, | ||||
|                     value: &mut <Self as ::fayalite::ty::Type>::SimValue, | ||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, | ||||
|                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||
|                 ) { | ||||
|                     #![allow(unused_mut, unused_variables)] | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); | ||||
|                     #(#sim_value_clone_from_bits_fields)* | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); | ||||
|                     #(#sim_value_clone_from_opaque_fields)* | ||||
|                 } | ||||
|                 fn sim_value_to_bits( | ||||
|                 fn sim_value_to_opaque<'__w>( | ||||
|                     &self, | ||||
|                     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)] | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); | ||||
|                     #(#sim_value_to_bits_fields)* | ||||
|                     let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); | ||||
|                     #(#sim_value_to_opaque_fields)* | ||||
|                     v.finish() | ||||
|                 } | ||||
|             } | ||||
|             #[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 | ||||
|         { | ||||
|             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 { | ||||
|             quote_spanned! {span=> | ||||
|                 _ => ::fayalite::__std::unreachable!(), | ||||
|             } | ||||
|         }; | ||||
|         let sim_value_from_bits_match_arms = Vec::from_iter( | ||||
|         let sim_value_from_opaque_match_arms = Vec::from_iter( | ||||
|             variants | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|  | @ -729,29 +729,29 @@ impl ToTokens for ParsedEnum { | |||
|                         if let Some(_) = field { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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) | ||||
|                                 } | ||||
|                             } | ||||
|                         } else { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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 { | ||||
|                 quote_spanned! {span=> | ||||
|                     _ => 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 { | ||||
|                         *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!(), | ||||
|                 } | ||||
|             }; | ||||
|         let sim_value_clone_from_bits_match_arms = Vec::from_iter( | ||||
|         let sim_value_clone_from_opaque_match_arms = Vec::from_iter( | ||||
|             variants | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|  | @ -777,28 +777,28 @@ impl ToTokens for ParsedEnum { | |||
|                         if let Some(_) = field { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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 { | ||||
|                                     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); | ||||
|                                 }, | ||||
|                             } | ||||
|                         } else { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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 { | ||||
|                                     *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 | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|  | @ -815,13 +815,13 @@ impl ToTokens for ParsedEnum { | |||
|                         if let Some(_) = field { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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 { | ||||
|                             quote_spanned! {span=> | ||||
|                                 #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| { | ||||
|                         quote_spanned! {span=> | ||||
|                             #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 { | ||||
|                     ::fayalite::source_location::SourceLocation::caller() | ||||
|                 } | ||||
|                 fn sim_value_from_bits( | ||||
|                 fn sim_value_from_opaque( | ||||
|                     &self, | ||||
|                     bits: &::fayalite::bitvec::slice::BitSlice, | ||||
|                     opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, | ||||
|                 ) -> <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() { | ||||
|                         #(#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, | ||||
|                     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() { | ||||
|                         #(#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, | ||||
|                     value: &<Self as ::fayalite::ty::Type>::SimValue, | ||||
|                     bits: &mut ::fayalite::bitvec::slice::BitSlice, | ||||
|                 ) { | ||||
|                     let v = ::fayalite::enum_::EnumSimValueToBits::new(*self, bits); | ||||
|                     writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, | ||||
|                 ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { | ||||
|                     let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer); | ||||
|                     match value { | ||||
|                         #(#sim_value_to_bits_match_arms)* | ||||
|                         #(#sim_value_to_opaque_match_arms)* | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  |  | |||
|  | @ -12,12 +12,12 @@ use crate::{ | |||
|     sim::value::{SimValue, SimValuePartialEq}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{ | ||||
|         CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, | ||||
|         CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter, | ||||
|         OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref, | ||||
|         serde_impls::SerdeCanonicalType, | ||||
|     }, | ||||
|     util::ConstUsize, | ||||
| }; | ||||
| use bitvec::slice::BitSlice; | ||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; | ||||
| use std::{iter::FusedIterator, ops::Index}; | ||||
| 
 | ||||
|  | @ -48,15 +48,20 @@ impl<T: Type, Len: Size> ArrayType<T, Len> { | |||
|             is_storable, | ||||
|             is_castable_from_bits, | ||||
|             bit_width, | ||||
|             sim_only_values_len, | ||||
|         } = element; | ||||
|         let Some(bit_width) = bit_width.checked_mul(len) else { | ||||
|             panic!("array too big"); | ||||
|         }; | ||||
|         let Some(sim_only_values_len) = sim_only_values_len.checked_mul(len) else { | ||||
|             panic!("array too big"); | ||||
|         }; | ||||
|         TypeProperties { | ||||
|             is_passive, | ||||
|             is_storable, | ||||
|             is_castable_from_bits, | ||||
|             bit_width, | ||||
|             sim_only_values_len, | ||||
|         } | ||||
|     } | ||||
|     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() | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); | ||||
|         let element = self.element(); | ||||
|         let element_bit_width = element.canonical().bit_width(); | ||||
|         TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| { | ||||
|             SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width]) | ||||
|         }))) | ||||
|         .ok() | ||||
|         .expect("used correct length") | ||||
|     fn sim_value_from_opaque(&self, mut opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         let element_ty = self.element(); | ||||
|         let element_size = element_ty.canonical().size(); | ||||
|         let mut value = Vec::with_capacity(self.len()); | ||||
|         for _ in 0..self.len() { | ||||
|             let (element_opaque, rest) = opaque.split_at(element_size); | ||||
|             value.push(SimValue::from_opaque(element_ty, element_opaque.to_owned())); | ||||
|             opaque = rest; | ||||
|         } | ||||
|         value.try_into().ok().expect("used correct length") | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         value: &mut Self::SimValue, | ||||
|         mut opaque: OpaqueSimValueSlice<'_>, | ||||
|     ) { | ||||
|         let element_ty = self.element(); | ||||
|         let element_bit_width = element_ty.canonical().bit_width(); | ||||
|         let value: &mut [SimValue<T>] = value.as_mut(); | ||||
|         let element_size = element_ty.canonical().size(); | ||||
|         let value = AsMut::<[SimValue<T>]>::as_mut(value); | ||||
|         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); | ||||
|             SimValue::bits_mut(element_value) | ||||
|                 .bits_mut() | ||||
|                 .copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]); | ||||
|             let (element_opaque, rest) = opaque.split_at(element_size); | ||||
|             SimValue::opaque_mut(element_value).clone_from_slice(element_opaque); | ||||
|             opaque = rest; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { | ||||
|         assert_eq!(bits.len(), self.type_properties.bit_width); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         value: &Self::SimValue, | ||||
|         mut writer: OpaqueSimValueWriter<'w>, | ||||
|     ) -> OpaqueSimValueWritten<'w> { | ||||
|         let element_ty = self.element(); | ||||
|         let element_bit_width = element_ty.canonical().bit_width(); | ||||
|         let value: &[SimValue<T>] = value.as_ref(); | ||||
|         let element_size = element_ty.canonical().size(); | ||||
|         let value = AsRef::<[SimValue<T>]>::as_ref(value); | ||||
|         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); | ||||
|             bits[i * element_bit_width..][..element_bit_width] | ||||
|                 .copy_from_bitslice(SimValue::bits(element_value).bits()); | ||||
|             writer.fill_prefix_with(element_size, |writer| { | ||||
|                 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}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{ | ||||
|         CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, StaticType, Type, TypeProperties, | ||||
|         TypeWithDeref, impl_match_variant_as_self, | ||||
|         CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize, | ||||
|         OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, | ||||
|         TypeProperties, TypeWithDeref, impl_match_variant_as_self, | ||||
|     }, | ||||
|     util::HashMap, | ||||
| }; | ||||
| use bitvec::{slice::BitSlice, vec::BitVec}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::{fmt, marker::PhantomData}; | ||||
| 
 | ||||
|  | @ -69,7 +69,7 @@ impl fmt::Display for FmtDebugInStruct { | |||
| struct BundleImpl { | ||||
|     fields: Interned<[BundleField]>, | ||||
|     name_indexes: HashMap<Interned<str>, usize>, | ||||
|     field_offsets: Interned<[usize]>, | ||||
|     field_offsets: Interned<[OpaqueSimValueSize]>, | ||||
|     type_properties: TypeProperties, | ||||
| } | ||||
| 
 | ||||
|  | @ -89,12 +89,9 @@ impl std::fmt::Debug for BundleImpl { | |||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         f.write_str("Bundle ")?; | ||||
|         f.debug_set() | ||||
|             .entries( | ||||
|                 self.fields | ||||
|                     .iter() | ||||
|                     .enumerate() | ||||
|                     .map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])), | ||||
|             ) | ||||
|             .entries(self.fields.iter().enumerate().map(|(index, field)| { | ||||
|                 field.fmt_debug_in_struct(self.field_offsets[index].bit_width) | ||||
|             })) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | @ -119,6 +116,7 @@ impl BundleTypePropertiesBuilder { | |||
|             is_storable: true, | ||||
|             is_castable_from_bits: true, | ||||
|             bit_width: 0, | ||||
|             sim_only_values_len: 0, | ||||
|         }) | ||||
|     } | ||||
|     pub const fn clone(&self) -> Self { | ||||
|  | @ -126,8 +124,12 @@ impl BundleTypePropertiesBuilder { | |||
|     } | ||||
|     #[must_use] | ||||
|     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 { | ||||
|             panic!("bundle is too big: bit-width overflowed"); | ||||
|         let Some(OpaqueSimValueSize { | ||||
|             bit_width, | ||||
|             sim_only_values_len, | ||||
|         }) = self.0.size().checked_add(field_props.size()) | ||||
|         else { | ||||
|             panic!("bundle is too big: size overflowed"); | ||||
|         }; | ||||
|         if flipped { | ||||
|             Self(TypeProperties { | ||||
|  | @ -135,6 +137,7 @@ impl BundleTypePropertiesBuilder { | |||
|                 is_storable: false, | ||||
|                 is_castable_from_bits: false, | ||||
|                 bit_width, | ||||
|                 sim_only_values_len, | ||||
|             }) | ||||
|         } else { | ||||
|             Self(TypeProperties { | ||||
|  | @ -143,6 +146,7 @@ impl BundleTypePropertiesBuilder { | |||
|                 is_castable_from_bits: self.0.is_castable_from_bits | ||||
|                     & field_props.is_castable_from_bits, | ||||
|                 bit_width, | ||||
|                 sim_only_values_len, | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
|  | @ -167,7 +171,7 @@ impl Bundle { | |||
|             if let Some(old_index) = name_indexes.insert(name, 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()); | ||||
|         } | ||||
|         Self(Intern::intern_sized(BundleImpl { | ||||
|  | @ -183,7 +187,7 @@ impl Bundle { | |||
|     pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> { | ||||
|         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 | ||||
|     } | ||||
|     pub fn type_properties(self) -> TypeProperties { | ||||
|  | @ -241,19 +245,27 @@ impl Type for Bundle { | |||
|     fn source_location() -> SourceLocation { | ||||
|         SourceLocation::builtin() | ||||
|     } | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         OpaqueSimValue::from_bitslice(bits) | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert_eq!(self.type_properties().size(), opaque.size()); | ||||
|         opaque.to_owned() | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); | ||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         value: &mut Self::SimValue, | ||||
|         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) { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); | ||||
|         bits.copy_from_bitslice(value.bits().bits()); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         value: &Self::SimValue, | ||||
|         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]>; | ||||
| } | ||||
| 
 | ||||
| pub struct BundleSimValueFromBits<'a> { | ||||
| pub struct BundleSimValueFromOpaque<'a> { | ||||
|     fields: std::slice::Iter<'static, BundleField>, | ||||
|     bits: &'a BitSlice, | ||||
|     opaque: OpaqueSimValueSlice<'a>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> BundleSimValueFromBits<'a> { | ||||
| impl<'a> BundleSimValueFromOpaque<'a> { | ||||
|     #[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(); | ||||
|         assert_eq!( | ||||
|             bits.len(), | ||||
|             opaque.size(), | ||||
|             fields | ||||
|                 .iter() | ||||
|                 .map(|BundleField { ty, .. }| ty.bit_width()) | ||||
|                 .sum::<usize>() | ||||
|                 .map(|BundleField { ty, .. }| ty.size()) | ||||
|                 .sum::<OpaqueSimValueSize>() | ||||
|         ); | ||||
|         Self { | ||||
|             fields: Interned::into_inner(fields).iter(), | ||||
|             bits, | ||||
|             opaque, | ||||
|         } | ||||
|     } | ||||
|     #[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 { | ||||
|             name: _, | ||||
|             flipped: _, | ||||
|  | @ -294,59 +306,68 @@ impl<'a> BundleSimValueFromBits<'a> { | |||
|         else { | ||||
|             panic!("tried to read too many fields from BundleSimValueFromBits"); | ||||
|         }; | ||||
|         let (field_bits, rest) = self.bits.split_at(ty.bit_width()); | ||||
|         self.bits = rest; | ||||
|         (T::from_canonical(ty), field_bits) | ||||
|         let (field_opaque, rest) = self.opaque.split_at(ty.size()); | ||||
|         self.opaque = rest; | ||||
|         (T::from_canonical(ty), field_opaque) | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn field_from_bits<T: Type>(&mut self) -> SimValue<T> { | ||||
|         let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); | ||||
|         SimValue::from_bitslice(field_ty, field_bits) | ||||
|     pub fn field_from_opaque<T: Type>(&mut self) -> SimValue<T> { | ||||
|         let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>(); | ||||
|         SimValue::from_opaque(field_ty, field_opaque.to_owned()) | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn field_clone_from_bits<T: Type>(&mut self, field_value: &mut SimValue<T>) { | ||||
|         let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); | ||||
|     pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) { | ||||
|         let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>(); | ||||
|         assert_eq!(field_ty, SimValue::ty(field_value)); | ||||
|         SimValue::bits_mut(field_value) | ||||
|             .bits_mut() | ||||
|             .copy_from_bitslice(field_bits); | ||||
|         SimValue::opaque_mut(field_value).clone_from_slice(field_opaque); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct BundleSimValueToBits<'a> { | ||||
| pub struct BundleSimValueToOpaque<'a> { | ||||
|     fields: std::slice::Iter<'static, BundleField>, | ||||
|     bits: &'a mut BitSlice, | ||||
|     writer: OpaqueSimValueWriter<'a>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> BundleSimValueToBits<'a> { | ||||
| impl<'a> BundleSimValueToOpaque<'a> { | ||||
|     #[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(); | ||||
|         assert_eq!( | ||||
|             bits.len(), | ||||
|             writer.size(), | ||||
|             fields | ||||
|                 .iter() | ||||
|                 .map(|BundleField { ty, .. }| ty.bit_width()) | ||||
|                 .sum::<usize>() | ||||
|                 .map(|BundleField { ty, .. }| ty.size()) | ||||
|                 .sum::<OpaqueSimValueSize>() | ||||
|         ); | ||||
|         Self { | ||||
|             fields: Interned::into_inner(fields).iter(), | ||||
|             bits, | ||||
|             writer, | ||||
|         } | ||||
|     } | ||||
|     #[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 { | ||||
|             name: _, | ||||
|             flipped: _, | ||||
|             ty, | ||||
|         }) = self.fields.next() | ||||
|         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)); | ||||
|         self.bits[..ty.bit_width()].copy_from_bitslice(SimValue::bits(field_value).bits()); | ||||
|         self.bits = &mut std::mem::take(&mut self.bits)[ty.bit_width()..]; | ||||
|         self.writer.fill_prefix_with(ty.size(), |writer| { | ||||
|             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 { | ||||
|                 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)] | ||||
|                 let mut v = BundleSimValueFromBits::new(*self, bits); | ||||
|                 $(let $var = v.field_from_bits();)* | ||||
|                 let mut v = BundleSimValueFromOpaque::new(*self, opaque); | ||||
|                 $(let $var = v.field_from_opaque();)* | ||||
|                 ($($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)] | ||||
|                 let mut v = BundleSimValueFromBits::new(*self, bits); | ||||
|                 let mut v = BundleSimValueFromOpaque::new(*self, opaque); | ||||
|                 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)] | ||||
|                 let mut v = BundleSimValueToBits::new(*self, bits); | ||||
|                 let mut v = BundleSimValueToOpaque::new(*self, writer); | ||||
|                 let ($($var,)*) = value; | ||||
|                 $(v.field_to_bits($var);)* | ||||
|                 $(v.field($var);)* | ||||
|                 v.finish() | ||||
|             } | ||||
|         } | ||||
|         impl<$($T: Type,)*> BundleType for ($($T,)*) { | ||||
|  | @ -592,12 +622,12 @@ macro_rules! impl_tuples { | |||
|                 let [$($ty_var,)*] = *ty.fields() else { | ||||
|                     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); | ||||
|                 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,)*) { | ||||
|  | @ -723,15 +753,23 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { | |||
|     fn source_location() -> SourceLocation { | ||||
|         SourceLocation::builtin() | ||||
|     } | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert!(opaque.is_empty()); | ||||
|         *self | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         _value: &mut Self::SimValue, | ||||
|         opaque: OpaqueSimValueSlice<'_>, | ||||
|     ) { | ||||
|         assert!(opaque.is_empty()); | ||||
|     } | ||||
|     fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &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] | ||||
|     fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { | ||||
|         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> { | ||||
|     #[track_caller] | ||||
|     fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|         let ty = Bundle::from_canonical(ty); | ||||
|     fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue<CanonicalType> { | ||||
|         let ty = Bundle::from_canonical(canonical_ty); | ||||
|         assert!(ty.fields().is_empty()); | ||||
|         SimValue::into_canonical(ToSimValueWithType::into_sim_value_with_type( | ||||
|             BitVec::new(), | ||||
|             ty, | ||||
|         )) | ||||
|         SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty()) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -6,9 +6,12 @@ use crate::{ | |||
|     int::Bool, | ||||
|     reset::{Reset, ResetType}, | ||||
|     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)] | ||||
| pub struct Clock; | ||||
|  | @ -39,19 +42,29 @@ impl Type for Clock { | |||
|         retval | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         bits[0] | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||
|         opaque.bits()[0] | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         *value = bits[0]; | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         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) { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         bits.set(0, *value); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         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_castable_from_bits: true, | ||||
|         bit_width: 1, | ||||
|         sim_only_values_len: 0, | ||||
|     }; | ||||
|     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||
| } | ||||
|  |  | |||
|  | @ -16,7 +16,8 @@ use crate::{ | |||
|     sim::value::{SimValue, SimValuePartialEq}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{ | ||||
|         CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type, | ||||
|         CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize, | ||||
|         OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, | ||||
|         TypeProperties, | ||||
|     }, | ||||
|     util::HashMap, | ||||
|  | @ -120,6 +121,7 @@ impl EnumTypePropertiesBuilder { | |||
|                 is_storable: true, | ||||
|                 is_castable_from_bits: true, | ||||
|                 bit_width: 0, | ||||
|                 sim_only_values_len: 0, | ||||
|             }, | ||||
|             variant_count: 0, | ||||
|         } | ||||
|  | @ -138,9 +140,14 @@ impl EnumTypePropertiesBuilder { | |||
|             is_storable, | ||||
|             is_castable_from_bits, | ||||
|             bit_width, | ||||
|             sim_only_values_len, | ||||
|         }) = field_props | ||||
|         { | ||||
|             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 { | ||||
|                 is_passive: true, | ||||
|                 is_storable: type_properties.is_storable & is_storable, | ||||
|  | @ -151,6 +158,7 @@ impl EnumTypePropertiesBuilder { | |||
|                 } else { | ||||
|                     type_properties.bit_width | ||||
|                 }, | ||||
|                 sim_only_values_len: 0, | ||||
|             }; | ||||
|         } | ||||
|         Self { | ||||
|  | @ -381,19 +389,27 @@ impl Type for Enum { | |||
|     fn source_location() -> SourceLocation { | ||||
|         SourceLocation::builtin() | ||||
|     } | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         OpaqueSimValue::from_bitslice(bits) | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert_eq!(self.type_properties().size(), opaque.size()); | ||||
|         opaque.to_owned() | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); | ||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         value: &mut Self::SimValue, | ||||
|         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) { | ||||
|         assert_eq!(bits.len(), self.type_properties().bit_width); | ||||
|         assert_eq!(value.bit_width(), self.type_properties().bit_width); | ||||
|         bits.copy_from_bitslice(value.bits().bits()); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         value: &Self::SimValue, | ||||
|         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]>, | ||||
|     discriminant: usize, | ||||
|     body_bits: &'a BitSlice, | ||||
| } | ||||
| 
 | ||||
| impl<'a> EnumSimValueFromBits<'a> { | ||||
| impl<'a> EnumSimValueFromOpaque<'a> { | ||||
|     #[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 bit_width = EnumTypePropertiesBuilder::new() | ||||
|         let size @ OpaqueSimValueSize { | ||||
|             bit_width: _, | ||||
|             sim_only_values_len: 0, | ||||
|         } = EnumTypePropertiesBuilder::new() | ||||
|             .variants(variants) | ||||
|             .finish() | ||||
|             .bit_width; | ||||
|         assert_eq!(bit_width, bits.len()); | ||||
|         let (discriminant_bits, body_bits) = | ||||
|             bits.split_at(discriminant_bit_width_impl(variants.len())); | ||||
|             .size() | ||||
|         else { | ||||
|             unreachable!(); | ||||
|         }; | ||||
|         assert_eq!(size, opaque.size()); | ||||
|         let (discriminant_bits, body_bits) = opaque | ||||
|             .bits() | ||||
|             .split_at(discriminant_bit_width_impl(variants.len())); | ||||
|         let mut discriminant = 0usize; | ||||
|         discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()] | ||||
|             .copy_from_bitslice(discriminant_bits); | ||||
|  | @ -517,7 +540,7 @@ impl<'a> EnumSimValueFromBits<'a> { | |||
|         (*ty, variant_bits, padding_bits) | ||||
|     } | ||||
|     #[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 { | ||||
|             self.usage_error(false); | ||||
|         }; | ||||
|  | @ -527,7 +550,7 @@ impl<'a> EnumSimValueFromBits<'a> { | |||
|         ) | ||||
|     } | ||||
|     #[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 { | ||||
|             self.usage_error(true); | ||||
|         }; | ||||
|  | @ -539,14 +562,14 @@ impl<'a> EnumSimValueFromBits<'a> { | |||
|             .copy_from_bitslice(self.body_bits); | ||||
|     } | ||||
|     #[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 { | ||||
|             self.usage_error(false); | ||||
|         }; | ||||
|         EnumPaddingSimValue::from_bitslice(padding_bits) | ||||
|     } | ||||
|     #[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 { | ||||
|             self.usage_error(false); | ||||
|         }; | ||||
|  | @ -566,14 +589,14 @@ impl<'a> EnumSimValueFromBits<'a> { | |||
|         } | ||||
|     } | ||||
|     #[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 { | ||||
|             self.usage_error(true); | ||||
|         }; | ||||
|         Self::clone_padding_from_bits(padding, padding_bits); | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn variant_with_field_clone_from_bits<T: Type>( | ||||
|     pub fn variant_with_field_clone_from_opaque<T: Type>( | ||||
|         self, | ||||
|         value: &mut SimValue<T>, | ||||
|         padding: &mut EnumPaddingSimValue, | ||||
|  | @ -589,35 +612,46 @@ impl<'a> EnumSimValueFromBits<'a> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct EnumSimValueToBits<'a> { | ||||
| pub struct EnumSimValueToOpaque<'a> { | ||||
|     variants: Interned<[EnumVariant]>, | ||||
|     bit_width: usize, | ||||
|     discriminant_bit_width: usize, | ||||
|     bits: &'a mut BitSlice, | ||||
|     writer: OpaqueSimValueWriter<'a>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> EnumSimValueToBits<'a> { | ||||
| impl<'a> EnumSimValueToOpaque<'a> { | ||||
|     #[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 bit_width = EnumTypePropertiesBuilder::new() | ||||
|         let size @ OpaqueSimValueSize { | ||||
|             bit_width, | ||||
|             sim_only_values_len: 0, | ||||
|         } = EnumTypePropertiesBuilder::new() | ||||
|             .variants(variants) | ||||
|             .finish() | ||||
|             .bit_width; | ||||
|         assert_eq!(bit_width, bits.len()); | ||||
|             .size() | ||||
|         else { | ||||
|             unreachable!(); | ||||
|         }; | ||||
|         assert_eq!(size, writer.size()); | ||||
|         Self { | ||||
|             variants, | ||||
|             bit_width, | ||||
|             discriminant_bit_width: discriminant_bit_width_impl(variants.len()), | ||||
|             bits, | ||||
|             writer, | ||||
|         } | ||||
|     } | ||||
|     #[track_caller] | ||||
|     fn discriminant_to_bits(&mut self, mut discriminant: usize) { | ||||
|     fn write_discriminant(&mut self, mut discriminant: usize) { | ||||
|         let orig_discriminant = discriminant; | ||||
|         let discriminant_bits = | ||||
|             &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); | ||||
|         assert!( | ||||
|             discriminant == 0, | ||||
|  | @ -625,8 +659,11 @@ impl<'a> EnumSimValueToBits<'a> { | |||
|         ); | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn unknown_variant_to_bits(mut self, value: &UnknownVariantSimValue) { | ||||
|         self.discriminant_to_bits(value.discriminant); | ||||
|     pub fn unknown_variant_to_opaque( | ||||
|         mut self, | ||||
|         value: &UnknownVariantSimValue, | ||||
|     ) -> OpaqueSimValueWritten<'a> { | ||||
|         self.write_discriminant(value.discriminant); | ||||
|         let None = self.variants.get(value.discriminant) else { | ||||
|             panic!("can't use UnknownVariantSimValue to set known discriminant"); | ||||
|         }; | ||||
|  | @ -634,45 +671,57 @@ impl<'a> EnumSimValueToBits<'a> { | |||
|             self.bit_width - self.discriminant_bit_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] | ||||
|     fn known_variant( | ||||
|         mut self, | ||||
|         discriminant: usize, | ||||
|         value: Option<&OpaqueSimValue>, | ||||
|         padding: &EnumPaddingSimValue, | ||||
|     ) -> (Option<CanonicalType>, &'a mut BitSlice) { | ||||
|         self.discriminant_to_bits(discriminant); | ||||
|     ) -> OpaqueSimValueWritten<'a> { | ||||
|         self.write_discriminant(discriminant); | ||||
|         let variant_ty = self.variants[discriminant].ty; | ||||
|         let variant_bit_width = variant_ty.map_or(0, CanonicalType::bit_width); | ||||
|         let padding_bits = &mut self.bits[self.discriminant_bit_width..][variant_bit_width..]; | ||||
|         if let Some(padding) = padding.bits() { | ||||
|             assert_eq!(padding.width(), padding_bits.len()); | ||||
|             padding_bits.copy_from_bitslice(padding.bits()); | ||||
|         } else { | ||||
|             padding_bits.fill(false); | ||||
|         } | ||||
|         let variant_bits = &mut self.bits[self.discriminant_bit_width..][..variant_bit_width]; | ||||
|         (variant_ty, variant_bits) | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn variant_no_field_to_bits(self, discriminant: usize, padding: &EnumPaddingSimValue) { | ||||
|         let (None, _variant_bits) = self.known_variant(discriminant, padding) else { | ||||
|         let variant_size = variant_ty.map_or(OpaqueSimValueSize::empty(), CanonicalType::size); | ||||
|         if let Some(value) = value { | ||||
|             if variant_ty.is_none() { | ||||
|                 panic!("expected variant to have no field"); | ||||
|         }; | ||||
|             } | ||||
|             self.writer.fill_prefix_with(variant_size, |writer| { | ||||
|                 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() | ||||
|         } | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn variant_with_field_to_bits<T: Type>( | ||||
|     pub fn variant_no_field_to_opaque( | ||||
|         self, | ||||
|         discriminant: usize, | ||||
|         padding: &EnumPaddingSimValue, | ||||
|     ) -> OpaqueSimValueWritten<'a> { | ||||
|         self.known_variant(discriminant, None, padding) | ||||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn variant_with_field_to_opaque<T: Type>( | ||||
|         self, | ||||
|         discriminant: usize, | ||||
|         value: &SimValue<T>, | ||||
|         padding: &EnumPaddingSimValue, | ||||
|     ) { | ||||
|         let (Some(variant_ty), variant_bits) = self.known_variant(discriminant, padding) else { | ||||
|             panic!("expected variant to have a field"); | ||||
|     ) -> OpaqueSimValueWritten<'a> { | ||||
|         let Some(variant_ty) = self.variants[discriminant].ty else { | ||||
|             panic!("expected variant to have no field"); | ||||
|         }; | ||||
|         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_type = FieldType::from_canonical(field.ty); | ||||
|         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| { | ||||
|             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}, | ||||
|     sim::value::{SimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, | ||||
|     util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit}, | ||||
|     ty::{ | ||||
|         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_traits::{One, Signed, Zero}; | ||||
| use serde::{ | ||||
|  | @ -26,7 +29,7 @@ use std::{ | |||
|     fmt, | ||||
|     marker::PhantomData, | ||||
|     num::NonZero, | ||||
|     ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive}, | ||||
|     ops::{Index, Not, Range, RangeBounds, RangeInclusive}, | ||||
|     str::FromStr, | ||||
|     sync::Arc, | ||||
| }; | ||||
|  | @ -645,6 +648,7 @@ macro_rules! impl_int { | |||
|                     is_storable: true, | ||||
|                     is_castable_from_bits: true, | ||||
|                     bit_width: self.width, | ||||
|                     sim_only_values_len: 0, | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -678,19 +682,36 @@ macro_rules! impl_int { | |||
|             fn source_location() -> SourceLocation { | ||||
|                 SourceLocation::builtin() | ||||
|             } | ||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|                 assert_eq!(bits.len(), self.width()); | ||||
|                 $value::new(Arc::new(bits.to_bitvec())) | ||||
|             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|                 assert_eq!( | ||||
|                     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) { | ||||
|                 assert_eq!(bits.len(), self.width()); | ||||
|             fn sim_value_clone_from_opaque( | ||||
|                 &self, | ||||
|                 value: &mut Self::SimValue, | ||||
|                 opaque: OpaqueSimValueSlice<'_>, | ||||
|             ) { | ||||
|                 assert_eq!( | ||||
|                     opaque.size(), | ||||
|                     OpaqueSimValueSize::from_bit_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) { | ||||
|                 assert_eq!(bits.len(), self.width()); | ||||
|             fn sim_value_to_opaque<'w>( | ||||
|                 &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()); | ||||
|                 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, | ||||
|                 } | ||||
|             } | ||||
|             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) | ||||
|     } | ||||
|     fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> { | ||||
|         let width = 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 | ||||
|         slice_range(index, self.width()) | ||||
|     } | ||||
|     fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) { | ||||
|         let range = self.slice_index_to_range(index); | ||||
|  | @ -1252,17 +1264,27 @@ impl Type for Bool { | |||
|     fn source_location() -> SourceLocation { | ||||
|         SourceLocation::builtin() | ||||
|     } | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         bits[0] | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||
|         opaque.bits()[0] | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         *value = bits[0]; | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         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) { | ||||
|         assert_eq!(bits.len(), 1); | ||||
|         bits.set(0, *value); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         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_castable_from_bits: true, | ||||
|         bit_width: 1, | ||||
|         sim_only_values_len: 0, | ||||
|     }; | ||||
|     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||
| } | ||||
|  |  | |||
|  | @ -12,9 +12,12 @@ use crate::{ | |||
|     phantom_const::PhantomConst, | ||||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, | ||||
|     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::{ | ||||
|     Deserialize, Deserializer, Serialize, Serializer, | ||||
|     de::{Error, Visitor, value::UsizeDeserializer}, | ||||
|  | @ -70,16 +73,24 @@ impl Type for UIntInRangeMaskType { | |||
|         SourceLocation::builtin() | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         Bool.sim_value_from_bits(bits) | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         Bool.sim_value_from_opaque(opaque) | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         Bool.sim_value_clone_from_bits(value, bits); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &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) { | ||||
|         Bool.sim_value_to_bits(value, bits); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &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() | ||||
|             } | ||||
| 
 | ||||
|             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; | ||||
|                 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 | ||||
|             } | ||||
| 
 | ||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|                 *value = self.sim_value_from_bits(bits); | ||||
|             fn sim_value_clone_from_opaque( | ||||
|                 &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) { | ||||
|                 bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]); | ||||
|             fn sim_value_to_opaque<'w>( | ||||
|                 &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::Reset(_) | ||||
|         | 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( | ||||
|             splat_mask(array.element(), value), | ||||
|             array.len(), | ||||
|  |  | |||
|  | @ -1524,7 +1524,8 @@ impl TargetState { | |||
|                 | CanonicalType::Clock(_) | ||||
|                 | CanonicalType::AsyncReset(_) | ||||
|                 | CanonicalType::SyncReset(_) | ||||
|                 | CanonicalType::Reset(_) => TargetStateInner::Single { | ||||
|                 | CanonicalType::Reset(_) | ||||
|                 | CanonicalType::DynSimOnlyValueType(_) => TargetStateInner::Single { | ||||
|                     declared_in_block, | ||||
|                     written_in_blocks: RefCell::default(), | ||||
|                 }, | ||||
|  |  | |||
|  | @ -11,11 +11,11 @@ use crate::{ | |||
|     sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, | ||||
|     source_location::SourceLocation, | ||||
|     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}, | ||||
|     }, | ||||
| }; | ||||
| use bitvec::slice::BitSlice; | ||||
| use serde::{ | ||||
|     Deserialize, Deserializer, Serialize, Serializer, | ||||
|     de::{DeserializeOwned, Error}, | ||||
|  | @ -284,19 +284,27 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> { | |||
|         SourceLocation::builtin() | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert!(opaque.is_empty()); | ||||
|         *self | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         value: &mut Self::SimValue, | ||||
|         opaque: OpaqueSimValueSlice<'_>, | ||||
|     ) { | ||||
|         assert!(opaque.is_empty()); | ||||
|         assert_eq!(*value, *self); | ||||
|     } | ||||
| 
 | ||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { | ||||
|         assert!(bits.is_empty()); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         value: &Self::SimValue, | ||||
|         writer: OpaqueSimValueWriter<'w>, | ||||
|     ) -> OpaqueSimValueWritten<'w> { | ||||
|         assert_eq!(*value, *self); | ||||
|         writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,9 +5,12 @@ use crate::{ | |||
|     expr::{Expr, ToExpr, ops}, | ||||
|     int::{Bool, SInt, UInt}, | ||||
|     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 { | ||||
|     pub trait ResetTypeSealed {} | ||||
|  | @ -69,19 +72,29 @@ macro_rules! reset_type { | |||
|                 retval | ||||
|             } | ||||
| 
 | ||||
|             fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|                 assert_eq!(bits.len(), 1); | ||||
|                 bits[0] | ||||
|             fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|                 assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); | ||||
|                 opaque.bits()[0] | ||||
|             } | ||||
| 
 | ||||
|             fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|                 assert_eq!(bits.len(), 1); | ||||
|                 *value = bits[0]; | ||||
|             fn sim_value_clone_from_opaque( | ||||
|                 &self, | ||||
|                 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) { | ||||
|                 assert_eq!(bits.len(), 1); | ||||
|                 bits.set(0, *value); | ||||
|             fn sim_value_to_opaque<'w>( | ||||
|                 &self, | ||||
|                 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_castable_from_bits: $is_castable_from_bits, | ||||
|                 bit_width: 1, | ||||
|                 sim_only_values_len: 0, | ||||
|             }; | ||||
|             const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||
|         } | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ use crate::{ | |||
|             TypeLen, | ||||
|         }, | ||||
|         time::{SimDuration, SimInstant}, | ||||
|         value::SimValue, | ||||
|         value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue}, | ||||
|     }, | ||||
|     util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, | ||||
| }; | ||||
|  | @ -503,6 +503,11 @@ pub trait TraceWriter: fmt::Debug + 'static { | |||
|         variant_index: usize, | ||||
|         ty: Enum, | ||||
|     ) -> Result<(), Self::Error>; | ||||
|     fn set_signal_sim_only_value( | ||||
|         &mut self, | ||||
|         id: TraceScalarId, | ||||
|         value: &DynSimOnlyValue, | ||||
|     ) -> Result<(), Self::Error>; | ||||
| } | ||||
| 
 | ||||
| pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>); | ||||
|  | @ -557,6 +562,11 @@ trait TraceWriterDynTrait: fmt::Debug + 'static { | |||
|         variant_index: usize, | ||||
|         ty: Enum, | ||||
|     ) -> 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 { | ||||
|  | @ -616,6 +626,13 @@ impl<T: TraceWriter> TraceWriterDynTrait for T { | |||
|                 .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>); | ||||
|  | @ -680,6 +697,13 @@ impl TraceWriter for DynTraceWriter { | |||
|         self.0 | ||||
|             .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)] | ||||
|  | @ -844,6 +868,10 @@ pub(crate) enum SimTraceKind { | |||
|         index: StatePartIndex<StatePartKindSmallSlots>, | ||||
|         ty: Enum, | ||||
|     }, | ||||
|     SimOnlyValue { | ||||
|         index: StatePartIndex<StatePartKindSmallSlots>, | ||||
|         ty: DynSimOnlyValueType, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| impl SimTraceKind { | ||||
|  | @ -866,6 +894,10 @@ impl SimTraceKind { | |||
|             SimTraceKind::EnumDiscriminant { index: _, ty } => { | ||||
|                 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>]>, | ||||
|     breakpoints: Option<BreakpointsSet>, | ||||
|     generator_waker: std::task::Waker, | ||||
|     sim_only_values: Vec<Option<DynSimOnlyValue>>, | ||||
|     free_sim_only_value_indexes: Vec<usize>, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Debug for SimulationImpl { | ||||
|  | @ -1440,6 +1474,8 @@ impl SimulationImpl { | |||
|             clocks_triggered, | ||||
|             breakpoints: _, | ||||
|             generator_waker: _, | ||||
|             sim_only_values, | ||||
|             free_sim_only_value_indexes, | ||||
|         } = self; | ||||
|         f.debug_struct("Simulation") | ||||
|             .field("state", state) | ||||
|  | @ -1453,6 +1489,8 @@ impl SimulationImpl { | |||
|             .field("trace_writers", trace_writers) | ||||
|             .field("instant", instant) | ||||
|             .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() | ||||
|     } | ||||
|     fn new(compiled: Compiled<Bundle>) -> Self { | ||||
|  | @ -1516,6 +1554,8 @@ impl SimulationImpl { | |||
|             clocks_triggered: compiled.clocks_triggered, | ||||
|             breakpoints: None, | ||||
|             generator_waker: Arc::new(GeneratorWaker).into(), | ||||
|             sim_only_values: vec![], | ||||
|             free_sim_only_value_indexes: vec![], | ||||
|         } | ||||
|     } | ||||
|     fn write_traces<const ONLY_IF_CHANGED: bool>( | ||||
|  | @ -1586,6 +1626,18 @@ impl SimulationImpl { | |||
|                         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) | ||||
|  | @ -1635,7 +1687,8 @@ impl SimulationImpl { | |||
|                 } | ||||
|                 SimTraceKind::SmallUInt { 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 bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); | ||||
|                     let bitslice = &bitslice[..state.len()]; | ||||
|  | @ -2050,6 +2103,7 @@ impl SimulationImpl { | |||
|                     CanonicalType::Reset(_) => false, | ||||
|                     CanonicalType::Clock(_) => false, | ||||
|                     CanonicalType::PhantomConst(_) => unreachable!(), | ||||
|                     CanonicalType::DynSimOnlyValueType(_) => false, | ||||
|                 }; | ||||
|                 let bit_indexes = | ||||
|                     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> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let Self { sim_impl, io } = self; | ||||
|  |  | |||
|  | @ -9,60 +9,82 @@ use crate::{ | |||
|     expr::{CastBitsTo, Expr, ToExpr}, | ||||
|     int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, | ||||
|     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::{ | ||||
|         ConstUsize, | ||||
|         ConstUsize, HashMap, | ||||
|         alternating_cell::{AlternatingCell, AlternatingCellMethods}, | ||||
|     }, | ||||
| }; | ||||
| 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::{ | ||||
|     fmt, | ||||
|     borrow::Cow, | ||||
|     fmt::{self, Write}, | ||||
|     hash::{BuildHasher, Hash, Hasher, RandomState}, | ||||
|     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)] | ||||
| enum ValidFlags { | ||||
|     BothValid = 0, | ||||
|     OnlyValueValid = 1, | ||||
|     OnlyBitsValid = 2, | ||||
|     OnlyOpaqueValid = 2, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct SimValueInner<T: Type> { | ||||
|     value: T::SimValue, | ||||
|     bits: UIntValue, | ||||
|     opaque: OpaqueSimValue, | ||||
|     valid_flags: ValidFlags, | ||||
|     ty: T, | ||||
|     sim_only_values_len: usize, | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|             ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {} | ||||
|             ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {} | ||||
|             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; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     fn into_bits(mut self) -> UIntValue { | ||||
|         self.fill_bits(); | ||||
|         self.bits | ||||
|     fn into_opaque(mut self) -> OpaqueSimValue { | ||||
|         self.fill_opaque(); | ||||
|         self.opaque | ||||
|     } | ||||
|     fn bits_mut(&mut self) -> &mut UIntValue { | ||||
|         self.fill_bits(); | ||||
|         self.valid_flags = ValidFlags::OnlyBitsValid; | ||||
|         &mut self.bits | ||||
|     fn opaque_mut(&mut self) -> &mut OpaqueSimValue { | ||||
|         self.fill_opaque(); | ||||
|         self.valid_flags = ValidFlags::OnlyOpaqueValid; | ||||
|         &mut self.opaque | ||||
|     } | ||||
|     fn fill_value(&mut self) { | ||||
|         match self.valid_flags { | ||||
|             ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} | ||||
|             ValidFlags::OnlyBitsValid => { | ||||
|             ValidFlags::OnlyOpaqueValid => { | ||||
|                 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; | ||||
|             } | ||||
|         } | ||||
|  | @ -83,11 +105,13 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> { | |||
|         match self.valid_flags { | ||||
|             ValidFlags::BothValid => return, | ||||
|             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 | ||||
|                 .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; | ||||
|     } | ||||
|  | @ -143,13 +167,15 @@ impl<T: Type + Clone> Clone for SimValue<T> { | |||
| 
 | ||||
| impl<T: Type> SimValue<T> { | ||||
|     #[track_caller] | ||||
|     pub fn from_bits(ty: T, bits: UIntValue) -> Self { | ||||
|         assert_eq!(ty.canonical().bit_width(), bits.width()); | ||||
|     pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self { | ||||
|         let size = ty.canonical().size(); | ||||
|         assert_eq!(size, opaque.size()); | ||||
|         let inner = SimValueInner { | ||||
|             value: ty.sim_value_from_bits(bits.bits()), | ||||
|             bits, | ||||
|             value: ty.sim_value_from_opaque(opaque.as_slice()), | ||||
|             opaque, | ||||
|             valid_flags: ValidFlags::BothValid, | ||||
|             ty, | ||||
|             sim_only_values_len: size.sim_only_values_len, | ||||
|         }; | ||||
|         Self { | ||||
|             inner: AlternatingCell::new_shared(inner), | ||||
|  | @ -157,14 +183,30 @@ impl<T: Type> SimValue<T> { | |||
|     } | ||||
|     #[track_caller] | ||||
|     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 { | ||||
|         let type_properties = ty.canonical().type_properties(); | ||||
|         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, | ||||
|             valid_flags: ValidFlags::OnlyValueValid, | ||||
|             ty, | ||||
|             sim_only_values_len: type_properties.sim_only_values_len, | ||||
|         }; | ||||
|         Self { | ||||
|             inner: AlternatingCell::new_unique(inner), | ||||
|  | @ -173,18 +215,24 @@ impl<T: Type> SimValue<T> { | |||
|     pub fn ty(this: &Self) -> T { | ||||
|         this.inner.share().ty | ||||
|     } | ||||
|     pub fn into_bits(this: Self) -> UIntValue { | ||||
|         this.inner.into_inner().into_bits() | ||||
|     pub fn into_opaque(this: Self) -> OpaqueSimValue { | ||||
|         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(); | ||||
|         (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 { | ||||
|         &this.inner.share().bits | ||||
|         Self::opaque(this).bits() | ||||
|     } | ||||
|     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 { | ||||
|         this.inner.into_inner().into_value() | ||||
|  | @ -197,59 +245,59 @@ impl<T: Type> SimValue<T> { | |||
|     } | ||||
|     #[track_caller] | ||||
|     pub fn from_canonical(v: SimValue<CanonicalType>) -> Self { | ||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); | ||||
|         Self::from_bits(T::from_canonical(ty), bits) | ||||
|         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||
|         Self::from_opaque(T::from_canonical(ty), opaque) | ||||
|     } | ||||
|     pub fn into_canonical(this: Self) -> SimValue<CanonicalType> { | ||||
|         let (ty, bits) = Self::into_ty_and_bits(this); | ||||
|         SimValue::from_bits(ty.canonical(), bits) | ||||
|         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||
|         SimValue::from_opaque(ty.canonical(), opaque) | ||||
|     } | ||||
|     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] | ||||
|     pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self | ||||
|     where | ||||
|         T: IntType, | ||||
|     { | ||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); | ||||
|         SimValue::from_bits(T::from_dyn_int(ty), bits) | ||||
|         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||
|         SimValue::from_opaque(T::from_dyn_int(ty), opaque) | ||||
|     } | ||||
|     pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn> | ||||
|     where | ||||
|         T: IntType, | ||||
|     { | ||||
|         let (ty, bits) = Self::into_ty_and_bits(this); | ||||
|         SimValue::from_bits(ty.as_dyn_int(), bits) | ||||
|         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||
|         SimValue::from_opaque(ty.as_dyn_int(), opaque) | ||||
|     } | ||||
|     pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn> | ||||
|     where | ||||
|         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] | ||||
|     pub fn from_bundle(v: SimValue<Bundle>) -> Self | ||||
|     where | ||||
|         T: BundleType, | ||||
|     { | ||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); | ||||
|         SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits) | ||||
|         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||
|         SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque) | ||||
|     } | ||||
|     pub fn into_bundle(this: Self) -> SimValue<Bundle> | ||||
|     where | ||||
|         T: BundleType, | ||||
|     { | ||||
|         let (ty, bits) = Self::into_ty_and_bits(this); | ||||
|         SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits) | ||||
|         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||
|         SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque) | ||||
|     } | ||||
|     pub fn to_bundle(this: &Self) -> SimValue<Bundle> | ||||
|     where | ||||
|         T: BundleType, | ||||
|     { | ||||
|         SimValue::from_bits( | ||||
|         SimValue::from_opaque( | ||||
|             Bundle::from_canonical(Self::ty(this).canonical()), | ||||
|             Self::bits(&this).clone(), | ||||
|             Self::opaque(&this).clone(), | ||||
|         ) | ||||
|     } | ||||
|     #[track_caller] | ||||
|  | @ -257,23 +305,23 @@ impl<T: Type> SimValue<T> { | |||
|     where | ||||
|         T: EnumType, | ||||
|     { | ||||
|         let (ty, bits) = SimValue::into_ty_and_bits(v); | ||||
|         SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits) | ||||
|         let (ty, opaque) = SimValue::into_ty_and_opaque(v); | ||||
|         SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque) | ||||
|     } | ||||
|     pub fn into_enum(this: Self) -> SimValue<Enum> | ||||
|     where | ||||
|         T: EnumType, | ||||
|     { | ||||
|         let (ty, bits) = Self::into_ty_and_bits(this); | ||||
|         SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits) | ||||
|         let (ty, opaque) = Self::into_ty_and_opaque(this); | ||||
|         SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque) | ||||
|     } | ||||
|     pub fn to_enum(this: &Self) -> SimValue<Enum> | ||||
|     where | ||||
|         T: EnumType, | ||||
|     { | ||||
|         SimValue::from_bits( | ||||
|         SimValue::from_opaque( | ||||
|             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] | ||||
|     fn to_expr(&self) -> Expr<Self::Type> { | ||||
|         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] | ||||
|     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] | ||||
|     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::Enum(_) | ||||
|             | CanonicalType::Bundle(_) | ||||
|             | CanonicalType::PhantomConst(_) => { | ||||
|             | CanonicalType::PhantomConst(_) | ||||
|             | CanonicalType::DynSimOnlyValueType(_) => { | ||||
|                 panic!("can't create SimValue from bool: expected value of type: {ty:?}"); | ||||
|             } | ||||
|             CanonicalType::Bool(_) | ||||
|             | CanonicalType::AsyncReset(_) | ||||
|             | CanonicalType::SyncReset(_) | ||||
|             | CanonicalType::Reset(_) | ||||
|             | CanonicalType::Clock(_) => { | ||||
|                 SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))) | ||||
|             } | ||||
|             | CanonicalType::Clock(_) => SimValue::from_opaque( | ||||
|                 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!(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, | ||||
|         TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, | ||||
|         time::{SimDuration, SimInstant}, | ||||
|         value::DynSimOnlyValue, | ||||
|     }, | ||||
|     util::HashMap, | ||||
| }; | ||||
|  | @ -1061,6 +1062,14 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> { | |||
|     ) -> Result<(), Self::Error> { | ||||
|         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> { | ||||
|  |  | |||
|  | @ -11,13 +11,21 @@ use crate::{ | |||
|     intern::{Intern, Interned}, | ||||
|     phantom_const::PhantomConst, | ||||
|     reset::{AsyncReset, Reset, SyncReset}, | ||||
|     sim::value::{SimValue, ToSimValueWithType}, | ||||
|     sim::value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType}, | ||||
|     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 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; | ||||
| 
 | ||||
|  | @ -28,6 +36,23 @@ pub struct TypeProperties { | |||
|     pub is_storable: bool, | ||||
|     pub is_castable_from_bits: bool, | ||||
|     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)] | ||||
|  | @ -43,6 +68,7 @@ pub enum CanonicalType { | |||
|     Reset(Reset), | ||||
|     Clock(Clock), | ||||
|     PhantomConst(PhantomConst), | ||||
|     DynSimOnlyValueType(DynSimOnlyValueType), | ||||
| } | ||||
| 
 | ||||
| impl fmt::Debug for CanonicalType { | ||||
|  | @ -59,6 +85,7 @@ impl fmt::Debug for CanonicalType { | |||
|             Self::Reset(v) => v.fmt(f), | ||||
|             Self::Clock(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::Clock(v) => v.type_properties(), | ||||
|             CanonicalType::PhantomConst(v) => v.type_properties(), | ||||
|             CanonicalType::DynSimOnlyValueType(v) => v.type_properties(), | ||||
|         } | ||||
|     } | ||||
|     pub fn is_passive(self) -> bool { | ||||
|  | @ -109,6 +137,12 @@ impl CanonicalType { | |||
|     pub fn bit_width(self) -> usize { | ||||
|         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 { | ||||
|         match self { | ||||
|             CanonicalType::UInt(lhs) => { | ||||
|  | @ -177,6 +211,12 @@ impl CanonicalType { | |||
|                 }; | ||||
|                 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 { | ||||
|  | @ -287,6 +327,7 @@ impl_base_type!(SyncReset); | |||
| impl_base_type!(Reset); | ||||
| impl_base_type!(Clock); | ||||
| impl_base_type!(PhantomConst); | ||||
| impl_base_type!(DynSimOnlyValueType); | ||||
| 
 | ||||
| impl_base_type_serde!(Bool, "a Bool"); | ||||
| impl_base_type_serde!(Enum, "an Enum"); | ||||
|  | @ -348,9 +389,17 @@ pub trait Type: | |||
|     fn canonical(&self) -> CanonicalType; | ||||
|     fn from_canonical(canonical_type: CanonicalType) -> Self; | ||||
|     fn source_location() -> SourceLocation; | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue; | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice); | ||||
|     fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice); | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue; | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &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: | ||||
|  | @ -405,6 +454,7 @@ impl Type for CanonicalType { | |||
|             CanonicalType::Reset(v) => v.mask_type().canonical(), | ||||
|             CanonicalType::Clock(v) => v.mask_type().canonical(), | ||||
|             CanonicalType::PhantomConst(v) => v.mask_type().canonical(), | ||||
|             CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(), | ||||
|         } | ||||
|     } | ||||
|     fn canonical(&self) -> CanonicalType { | ||||
|  | @ -416,28 +466,288 @@ impl Type for CanonicalType { | |||
|     fn source_location() -> SourceLocation { | ||||
|         SourceLocation::builtin() | ||||
|     } | ||||
|     fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { | ||||
|         assert_eq!(bits.len(), self.bit_width()); | ||||
|         OpaqueSimValue::from_bitslice(bits) | ||||
|     fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { | ||||
|         assert_eq!(self.type_properties().size(), opaque.size()); | ||||
|         opaque.to_owned() | ||||
|     } | ||||
|     fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { | ||||
|         assert_eq!(bits.len(), self.bit_width()); | ||||
|         assert_eq!(value.bit_width(), self.bit_width()); | ||||
|         value.bits_mut().bits_mut().copy_from_bitslice(bits); | ||||
|     fn sim_value_clone_from_opaque( | ||||
|         &self, | ||||
|         value: &mut Self::SimValue, | ||||
|         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) { | ||||
|         assert_eq!(bits.len(), self.bit_width()); | ||||
|         assert_eq!(value.bit_width(), self.bit_width()); | ||||
|         bits.copy_from_bitslice(value.bits().bits()); | ||||
|     fn sim_value_to_opaque<'w>( | ||||
|         &self, | ||||
|         value: &Self::SimValue, | ||||
|         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)] | ||||
| pub struct OpaqueSimValue { | ||||
|     bits: UIntValue, | ||||
|     #[serde(skip_serializing_if = "Vec::is_empty", default)] | ||||
|     sim_only_values: Vec<DynSimOnlyValue>, | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|         self.bits.width() | ||||
|     } | ||||
|  | @ -451,11 +761,109 @@ impl OpaqueSimValue { | |||
|         self.bits | ||||
|     } | ||||
|     pub fn from_bits(bits: UIntValue) -> Self { | ||||
|         Self { bits } | ||||
|         Self { | ||||
|             bits, | ||||
|             sim_only_values: Vec::new(), | ||||
|         } | ||||
|     } | ||||
|     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 { | ||||
|             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 { | ||||
|     const TYPE: Self; | ||||
|     const MASK_TYPE: Self::MaskType; | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ use crate::{ | |||
|     phantom_const::{PhantomConstCanonicalValue, PhantomConstValue}, | ||||
|     prelude::PhantomConst, | ||||
|     reset::{AsyncReset, Reset, SyncReset}, | ||||
|     sim::value::DynSimOnlyValueType, | ||||
|     ty::{BaseType, CanonicalType}, | ||||
| }; | ||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||
|  | @ -63,6 +64,7 @@ pub(crate) enum SerdeCanonicalType< | |||
|     Reset, | ||||
|     Clock, | ||||
|     PhantomConst(ThePhantomConst), | ||||
|     DynSimOnlyValueType(DynSimOnlyValueType), | ||||
| } | ||||
| 
 | ||||
| impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> { | ||||
|  | @ -79,6 +81,7 @@ impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomCo | |||
|             Self::Reset => "a Reset", | ||||
|             Self::Clock => "a Clock", | ||||
|             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::Clock(Clock {}) => Self::Clock, | ||||
|             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) => { | ||||
|                 Self::PhantomConst(PhantomConst::new(value.0)) | ||||
|             } | ||||
|             SerdeCanonicalType::DynSimOnlyValueType(value) => Self::DynSimOnlyValueType(value), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ pub use scoped_ref::ScopedRef; | |||
| #[doc(inline)] | ||||
| pub use misc::{ | ||||
|     BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, | ||||
|     iter_eq_by, | ||||
|     iter_eq_by, slice_range, try_slice_range, | ||||
| }; | ||||
| 
 | ||||
| pub mod job_server; | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView}; | |||
| use std::{ | ||||
|     cell::Cell, | ||||
|     fmt::{self, Debug, Write}, | ||||
|     ops::{Bound, Range, RangeBounds}, | ||||
|     rc::Rc, | ||||
|     sync::{Arc, OnceLock}, | ||||
| }; | ||||
|  | @ -209,3 +210,21 @@ impl std::io::Write for RcWriter { | |||
|         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